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"
43 #include "msvcrt/fcntl.h"
50 #include "wine/unicode.h"
54 #define REG_PROGRESS_VALUE 13200
55 #define COMPONENT_PROGRESS_VALUE 24000
57 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
62 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
);
63 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
);
64 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
);
65 static UINT
build_icon_path(MSIPACKAGE
*package
, LPCWSTR icon_name
,
71 typedef UINT (*STANDARDACTIONHANDLER
)(MSIPACKAGE
*);
73 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
);
74 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
);
75 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
);
76 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
);
77 static UINT
ACTION_FileCost(MSIPACKAGE
*package
);
78 static UINT
ACTION_InstallFiles(MSIPACKAGE
*package
);
79 static UINT
ACTION_DuplicateFiles(MSIPACKAGE
*package
);
80 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
);
81 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
);
82 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
);
83 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
);
84 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
);
85 static UINT
ACTION_RegisterClassInfo(MSIPACKAGE
*package
);
86 static UINT
ACTION_RegisterProgIdInfo(MSIPACKAGE
*package
);
87 static UINT
ACTION_RegisterExtensionInfo(MSIPACKAGE
*package
);
88 static UINT
ACTION_RegisterMIMEInfo(MSIPACKAGE
*package
);
89 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
);
90 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
);
91 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
);
92 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
);
93 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
);
94 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
);
95 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
);
96 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
);
97 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
);
98 static UINT
ACTION_ForceReboot(MSIPACKAGE
*package
);
99 static UINT
ACTION_ResolveSource(MSIPACKAGE
*package
);
100 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
);
101 static UINT
ACTION_RegisterFonts(MSIPACKAGE
*package
);
102 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
);
106 * consts and values used
108 static const WCHAR cszSourceDir
[] = {'S','o','u','r','c','e','D','i','r',0};
109 static const WCHAR cszRootDrive
[] = {'R','O','O','T','D','R','I','V','E',0};
110 static const WCHAR cszTargetDir
[] = {'T','A','R','G','E','T','D','I','R',0};
111 static const WCHAR cszTempFolder
[]= {'T','e','m','p','F','o','l','d','e','r',0};
112 static const WCHAR cszDatabase
[]={'D','A','T','A','B','A','S','E',0};
113 static const WCHAR c_colon
[] = {'C',':','\\',0};
114 static const WCHAR szProductCode
[]=
115 {'P','r','o','d','u','c','t','C','o','d','e',0};
116 static const WCHAR cszbs
[]={'\\',0};
117 const static WCHAR szCreateFolders
[] =
118 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
119 const static WCHAR szCostFinalize
[] =
120 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
121 const static WCHAR szInstallFiles
[] =
122 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
123 const static WCHAR szDuplicateFiles
[] =
124 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
125 const static WCHAR szWriteRegistryValues
[] =
126 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
127 'V','a','l','u','e','s',0};
128 const static WCHAR szCostInitialize
[] =
129 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
130 const static WCHAR szFileCost
[] =
131 {'F','i','l','e','C','o','s','t',0};
132 const static WCHAR szInstallInitialize
[] =
133 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
134 const static WCHAR szInstallValidate
[] =
135 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
136 const static WCHAR szLaunchConditions
[] =
137 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
138 const static WCHAR szProcessComponents
[] =
139 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
140 const static WCHAR szRegisterTypeLibraries
[] =
141 {'R','e','g','i','s','t','e','r','T','y','p','e',
142 'L','i','b','r','a','r','i','e','s',0};
143 const static WCHAR szRegisterClassInfo
[] =
144 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
145 const static WCHAR szRegisterProgIdInfo
[] =
146 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
147 const static WCHAR szCreateShortcuts
[] =
148 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
149 const static WCHAR szPublishProduct
[] =
150 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
151 const static WCHAR szWriteIniValues
[] =
152 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
153 const static WCHAR szSelfRegModules
[] =
154 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
155 const static WCHAR szPublishFeatures
[] =
156 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
157 const static WCHAR szRegisterProduct
[] =
158 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
159 const static WCHAR szInstallExecute
[] =
160 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
161 const static WCHAR szInstallExecuteAgain
[] =
162 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
163 'A','g','a','i','n',0};
164 const static WCHAR szInstallFinalize
[] =
165 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
166 const static WCHAR szForceReboot
[] =
167 {'F','o','r','c','e','R','e','b','o','o','t',0};
168 const static WCHAR szResolveSource
[] =
169 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
170 const static WCHAR szAppSearch
[] =
171 {'A','p','p','S','e','a','r','c','h',0};
172 const static WCHAR szAllocateRegistrySpace
[] =
173 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
174 'S','p','a','c','e',0};
175 const static WCHAR szBindImage
[] =
176 {'B','i','n','d','I','m','a','g','e',0};
177 const static WCHAR szCCPSearch
[] =
178 {'C','C','P','S','e','a','r','c','h',0};
179 const static WCHAR szDeleteServices
[] =
180 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
181 const static WCHAR szDisableRollback
[] =
182 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
183 const static WCHAR szExecuteAction
[] =
184 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
185 const static WCHAR szFindRelatedProducts
[] =
186 {'F','i','n','d','R','e','l','a','t','e','d',
187 'P','r','o','d','u','c','t','s',0};
188 const static WCHAR szInstallAdminPackage
[] =
189 {'I','n','s','t','a','l','l','A','d','m','i','n',
190 'P','a','c','k','a','g','e',0};
191 const static WCHAR szInstallSFPCatalogFile
[] =
192 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
194 const static WCHAR szIsolateComponents
[] =
195 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
196 const static WCHAR szMigrateFeatureStates
[] =
197 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
198 'S','t','a','t','e','s',0};
199 const static WCHAR szMoveFiles
[] =
200 {'M','o','v','e','F','i','l','e','s',0};
201 const static WCHAR szMsiPublishAssemblies
[] =
202 {'M','s','i','P','u','b','l','i','s','h',
203 'A','s','s','e','m','b','l','i','e','s',0};
204 const static WCHAR szMsiUnpublishAssemblies
[] =
205 {'M','s','i','U','n','p','u','b','l','i','s','h',
206 'A','s','s','e','m','b','l','i','e','s',0};
207 const static WCHAR szInstallODBC
[] =
208 {'I','n','s','t','a','l','l','O','D','B','C',0};
209 const static WCHAR szInstallServices
[] =
210 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
211 const static WCHAR szPatchFiles
[] =
212 {'P','a','t','c','h','F','i','l','e','s',0};
213 const static WCHAR szPublishComponents
[] =
214 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
215 const static WCHAR szRegisterComPlus
[] =
216 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
217 const static WCHAR szRegisterExtensionInfo
[] =
218 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
220 const static WCHAR szRegisterFonts
[] =
221 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
222 const static WCHAR szRegisterMIMEInfo
[] =
223 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
224 const static WCHAR szRegisterUser
[] =
225 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
226 const static WCHAR szRemoveDuplicateFiles
[] =
227 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
228 'F','i','l','e','s',0};
229 const static WCHAR szRemoveEnvironmentStrings
[] =
230 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
231 'S','t','r','i','n','g','s',0};
232 const static WCHAR szRemoveExistingProducts
[] =
233 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
234 'P','r','o','d','u','c','t','s',0};
235 const static WCHAR szRemoveFiles
[] =
236 {'R','e','m','o','v','e','F','i','l','e','s',0};
237 const static WCHAR szRemoveFolders
[] =
238 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
239 const static WCHAR szRemoveIniValues
[] =
240 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
241 const static WCHAR szRemoveODBC
[] =
242 {'R','e','m','o','v','e','O','D','B','C',0};
243 const static WCHAR szRemoveRegistryValues
[] =
244 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
245 'V','a','l','u','e','s',0};
246 const static WCHAR szRemoveShortcuts
[] =
247 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
248 const static WCHAR szRMCCPSearch
[] =
249 {'R','M','C','C','P','S','e','a','r','c','h',0};
250 const static WCHAR szScheduleReboot
[] =
251 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
252 const static WCHAR szSelfUnregModules
[] =
253 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
254 const static WCHAR szSetODBCFolders
[] =
255 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
256 const static WCHAR szStartServices
[] =
257 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
258 const static WCHAR szStopServices
[] =
259 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
260 const static WCHAR szUnpublishComponents
[] =
261 {'U','n','p','u','b','l','i','s','h',
262 'C','o','m','p','o','n','e','n','t','s',0};
263 const static WCHAR szUnpublishFeatures
[] =
264 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
265 const static WCHAR szUnregisterClassInfo
[] =
266 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
268 const static WCHAR szUnregisterComPlus
[] =
269 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
270 const static WCHAR szUnregisterExtensionInfo
[] =
271 {'U','n','r','e','g','i','s','t','e','r',
272 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
273 const static WCHAR szUnregisterFonts
[] =
274 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
275 const static WCHAR szUnregisterMIMEInfo
[] =
276 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
277 const static WCHAR szUnregisterProgIdInfo
[] =
278 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
280 const static WCHAR szUnregisterTypeLibraries
[] =
281 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
282 'L','i','b','r','a','r','i','e','s',0};
283 const static WCHAR szValidateProductID
[] =
284 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
285 const static WCHAR szWriteEnvironmentStrings
[] =
286 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
287 'S','t','r','i','n','g','s',0};
291 STANDARDACTIONHANDLER handler
;
294 static struct _actions StandardActions
[] = {
295 { szAllocateRegistrySpace
, NULL
},
296 { szAppSearch
, ACTION_AppSearch
},
297 { szBindImage
, NULL
},
298 { szCCPSearch
, NULL
},
299 { szCostFinalize
, ACTION_CostFinalize
},
300 { szCostInitialize
, ACTION_CostInitialize
},
301 { szCreateFolders
, ACTION_CreateFolders
},
302 { szCreateShortcuts
, ACTION_CreateShortcuts
},
303 { szDeleteServices
, NULL
},
304 { szDisableRollback
, NULL
},
305 { szDuplicateFiles
, ACTION_DuplicateFiles
},
306 { szExecuteAction
, ACTION_ExecuteAction
},
307 { szFileCost
, ACTION_FileCost
},
308 { szFindRelatedProducts
, ACTION_FindRelatedProducts
},
309 { szForceReboot
, ACTION_ForceReboot
},
310 { szInstallAdminPackage
, NULL
},
311 { szInstallExecute
, ACTION_InstallExecute
},
312 { szInstallExecuteAgain
, ACTION_InstallExecute
},
313 { szInstallFiles
, ACTION_InstallFiles
},
314 { szInstallFinalize
, ACTION_InstallFinalize
},
315 { szInstallInitialize
, ACTION_InstallInitialize
},
316 { szInstallSFPCatalogFile
, NULL
},
317 { szInstallValidate
, ACTION_InstallValidate
},
318 { szIsolateComponents
, NULL
},
319 { szLaunchConditions
, ACTION_LaunchConditions
},
320 { szMigrateFeatureStates
, NULL
},
321 { szMoveFiles
, NULL
},
322 { szMsiPublishAssemblies
, NULL
},
323 { szMsiUnpublishAssemblies
, NULL
},
324 { szInstallODBC
, NULL
},
325 { szInstallServices
, NULL
},
326 { szPatchFiles
, NULL
},
327 { szProcessComponents
, ACTION_ProcessComponents
},
328 { szPublishComponents
, ACTION_PublishComponents
},
329 { szPublishFeatures
, ACTION_PublishFeatures
},
330 { szPublishProduct
, ACTION_PublishProduct
},
331 { szRegisterClassInfo
, ACTION_RegisterClassInfo
},
332 { szRegisterComPlus
, NULL
},
333 { szRegisterExtensionInfo
, ACTION_RegisterExtensionInfo
},
334 { szRegisterFonts
, ACTION_RegisterFonts
},
335 { szRegisterMIMEInfo
, ACTION_RegisterMIMEInfo
},
336 { szRegisterProduct
, ACTION_RegisterProduct
},
337 { szRegisterProgIdInfo
, ACTION_RegisterProgIdInfo
},
338 { szRegisterTypeLibraries
, ACTION_RegisterTypeLibraries
},
339 { szRegisterUser
, ACTION_RegisterUser
},
340 { szRemoveDuplicateFiles
, NULL
},
341 { szRemoveEnvironmentStrings
, NULL
},
342 { szRemoveExistingProducts
, NULL
},
343 { szRemoveFiles
, NULL
},
344 { szRemoveFolders
, NULL
},
345 { szRemoveIniValues
, NULL
},
346 { szRemoveODBC
, NULL
},
347 { szRemoveRegistryValues
, NULL
},
348 { szRemoveShortcuts
, NULL
},
349 { szResolveSource
, ACTION_ResolveSource
},
350 { szRMCCPSearch
, NULL
},
351 { szScheduleReboot
, NULL
},
352 { szSelfRegModules
, ACTION_SelfRegModules
},
353 { szSelfUnregModules
, NULL
},
354 { szSetODBCFolders
, NULL
},
355 { szStartServices
, NULL
},
356 { szStopServices
, NULL
},
357 { szUnpublishComponents
, NULL
},
358 { szUnpublishFeatures
, NULL
},
359 { szUnregisterClassInfo
, NULL
},
360 { szUnregisterComPlus
, NULL
},
361 { szUnregisterExtensionInfo
, NULL
},
362 { szUnregisterFonts
, NULL
},
363 { szUnregisterMIMEInfo
, NULL
},
364 { szUnregisterProgIdInfo
, NULL
},
365 { szUnregisterTypeLibraries
, NULL
},
366 { szValidateProductID
, NULL
},
367 { szWriteEnvironmentStrings
, NULL
},
368 { szWriteIniValues
, ACTION_WriteIniValues
},
369 { szWriteRegistryValues
, ACTION_WriteRegistryValues
},
374 /********************************************************
375 * helper functions to get around current HACKS and such
376 ********************************************************/
377 inline static void reduce_to_longfilename(WCHAR
* filename
)
379 LPWSTR p
= strchrW(filename
,'|');
381 memmove(filename
, p
+1, (strlenW(p
+1)+1)*sizeof(WCHAR
));
384 inline static void reduce_to_shortfilename(WCHAR
* filename
)
386 LPWSTR p
= strchrW(filename
,'|');
391 WCHAR
*load_dynamic_stringW(MSIRECORD
*row
, INT index
)
398 if (MSI_RecordIsNull(row
,index
))
401 rc
= MSI_RecordGetStringW(row
,index
,NULL
,&sz
);
403 /* having an empty string is different than NULL */
406 ret
= HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR
));
412 ret
= HeapAlloc(GetProcessHeap(),0,sz
* sizeof (WCHAR
));
413 rc
= MSI_RecordGetStringW(row
,index
,ret
,&sz
);
414 if (rc
!=ERROR_SUCCESS
)
416 ERR("Unable to load dynamic string\n");
417 HeapFree(GetProcessHeap(), 0, ret
);
423 LPWSTR
load_dynamic_property(MSIPACKAGE
*package
, LPCWSTR prop
, UINT
* rc
)
429 r
= MSI_GetPropertyW(package
, prop
, NULL
, &sz
);
430 if (r
!= ERROR_SUCCESS
&& r
!= ERROR_MORE_DATA
)
437 str
= HeapAlloc(GetProcessHeap(),0,sz
*sizeof(WCHAR
));
438 r
= MSI_GetPropertyW(package
, prop
, str
, &sz
);
439 if (r
!= ERROR_SUCCESS
)
441 HeapFree(GetProcessHeap(),0,str
);
449 int get_loaded_component(MSIPACKAGE
* package
, LPCWSTR Component
)
454 for (i
= 0; i
< package
->loaded_components
; i
++)
456 if (strcmpW(Component
,package
->components
[i
].Component
)==0)
465 int get_loaded_feature(MSIPACKAGE
* package
, LPCWSTR Feature
)
470 for (i
= 0; i
< package
->loaded_features
; i
++)
472 if (strcmpW(Feature
,package
->features
[i
].Feature
)==0)
481 int get_loaded_file(MSIPACKAGE
* package
, LPCWSTR file
)
486 for (i
= 0; i
< package
->loaded_files
; i
++)
488 if (strcmpW(file
,package
->files
[i
].File
)==0)
497 int track_tempfile(MSIPACKAGE
*package
, LPCWSTR name
, LPCWSTR path
)
505 for (i
=0; i
< package
->loaded_files
; i
++)
506 if (strcmpW(package
->files
[i
].File
,name
)==0)
509 index
= package
->loaded_files
;
510 package
->loaded_files
++;
511 if (package
->loaded_files
== 1)
512 package
->files
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE
));
514 package
->files
= HeapReAlloc(GetProcessHeap(),0,
515 package
->files
, package
->loaded_files
* sizeof(MSIFILE
));
517 memset(&package
->files
[index
],0,sizeof(MSIFILE
));
519 package
->files
[index
].File
= strdupW(name
);
520 package
->files
[index
].TargetPath
= strdupW(path
);
521 package
->files
[index
].Temporary
= TRUE
;
523 TRACE("Tracking tempfile (%s)\n",debugstr_w(package
->files
[index
].File
));
528 static void remove_tracked_tempfiles(MSIPACKAGE
* package
)
535 for (i
= 0; i
< package
->loaded_files
; i
++)
537 if (package
->files
[i
].Temporary
)
539 TRACE("Cleaning up %s\n",debugstr_w(package
->files
[i
].TargetPath
));
540 DeleteFileW(package
->files
[i
].TargetPath
);
546 /* wrapper to resist a need for a full rewrite right now */
547 DWORD
deformat_string(MSIPACKAGE
*package
, LPCWSTR ptr
, WCHAR
** data
)
551 MSIRECORD
*rec
= MSI_CreateRecord(1);
554 MSI_RecordSetStringW(rec
,0,ptr
);
555 MSI_FormatRecordW(package
,rec
,NULL
,&size
);
559 *data
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
561 MSI_FormatRecordW(package
,rec
,*data
,&size
);
564 msiobj_release( &rec
->hdr
);
565 return sizeof(WCHAR
)*size
;
567 msiobj_release( &rec
->hdr
);
574 DWORD
build_version_dword(LPCWSTR version_string
)
578 DWORD rc
= 0x00000000;
581 ptr1
= version_string
;
590 ptr1
= strchrW(ptr1
,'.');
600 ptr1
= strchrW(ptr1
,'.');
610 rc
= MAKELONG(build
,MAKEWORD(minor
,major
));
611 TRACE("%s -> 0x%lx\n",debugstr_w(version_string
),rc
);
615 /* Called when the package is being closed */
616 void ACTION_free_package_structures( MSIPACKAGE
* package
)
620 TRACE("Freeing package action data\n");
622 remove_tracked_tempfiles(package
);
624 /* No dynamic buffers in features */
625 if (package
->features
&& package
->loaded_features
> 0)
626 HeapFree(GetProcessHeap(),0,package
->features
);
628 for (i
= 0; i
< package
->loaded_folders
; i
++)
630 HeapFree(GetProcessHeap(),0,package
->folders
[i
].Directory
);
631 HeapFree(GetProcessHeap(),0,package
->folders
[i
].TargetDefault
);
632 HeapFree(GetProcessHeap(),0,package
->folders
[i
].SourceDefault
);
633 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedTarget
);
634 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedSource
);
635 HeapFree(GetProcessHeap(),0,package
->folders
[i
].Property
);
637 if (package
->folders
&& package
->loaded_folders
> 0)
638 HeapFree(GetProcessHeap(),0,package
->folders
);
640 for (i
= 0; i
< package
->loaded_components
; i
++)
641 HeapFree(GetProcessHeap(),0,package
->components
[i
].FullKeypath
);
643 if (package
->components
&& package
->loaded_components
> 0)
644 HeapFree(GetProcessHeap(),0,package
->components
);
646 for (i
= 0; i
< package
->loaded_files
; i
++)
648 HeapFree(GetProcessHeap(),0,package
->files
[i
].File
);
649 HeapFree(GetProcessHeap(),0,package
->files
[i
].FileName
);
650 HeapFree(GetProcessHeap(),0,package
->files
[i
].ShortName
);
651 HeapFree(GetProcessHeap(),0,package
->files
[i
].Version
);
652 HeapFree(GetProcessHeap(),0,package
->files
[i
].Language
);
653 HeapFree(GetProcessHeap(),0,package
->files
[i
].SourcePath
);
654 HeapFree(GetProcessHeap(),0,package
->files
[i
].TargetPath
);
657 if (package
->files
&& package
->loaded_files
> 0)
658 HeapFree(GetProcessHeap(),0,package
->files
);
660 /* clean up extension, progid, class and verb structures */
661 for (i
= 0; i
< package
->loaded_classes
; i
++)
663 HeapFree(GetProcessHeap(),0,package
->classes
[i
].Description
);
664 HeapFree(GetProcessHeap(),0,package
->classes
[i
].FileTypeMask
);
665 HeapFree(GetProcessHeap(),0,package
->classes
[i
].IconPath
);
666 HeapFree(GetProcessHeap(),0,package
->classes
[i
].DefInprocHandler
);
667 HeapFree(GetProcessHeap(),0,package
->classes
[i
].DefInprocHandler32
);
668 HeapFree(GetProcessHeap(),0,package
->classes
[i
].Argument
);
669 HeapFree(GetProcessHeap(),0,package
->classes
[i
].ProgIDText
);
672 if (package
->classes
&& package
->loaded_classes
> 0)
673 HeapFree(GetProcessHeap(),0,package
->classes
);
675 for (i
= 0; i
< package
->loaded_extensions
; i
++)
677 HeapFree(GetProcessHeap(),0,package
->extensions
[i
].ProgIDText
);
680 if (package
->extensions
&& package
->loaded_extensions
> 0)
681 HeapFree(GetProcessHeap(),0,package
->extensions
);
683 for (i
= 0; i
< package
->loaded_progids
; i
++)
685 HeapFree(GetProcessHeap(),0,package
->progids
[i
].ProgID
);
686 HeapFree(GetProcessHeap(),0,package
->progids
[i
].Description
);
687 HeapFree(GetProcessHeap(),0,package
->progids
[i
].IconPath
);
690 if (package
->progids
&& package
->loaded_progids
> 0)
691 HeapFree(GetProcessHeap(),0,package
->progids
);
693 for (i
= 0; i
< package
->loaded_verbs
; i
++)
695 HeapFree(GetProcessHeap(),0,package
->verbs
[i
].Verb
);
696 HeapFree(GetProcessHeap(),0,package
->verbs
[i
].Command
);
697 HeapFree(GetProcessHeap(),0,package
->verbs
[i
].Argument
);
700 if (package
->verbs
&& package
->loaded_verbs
> 0)
701 HeapFree(GetProcessHeap(),0,package
->verbs
);
703 for (i
= 0; i
< package
->loaded_mimes
; i
++)
704 HeapFree(GetProcessHeap(),0,package
->mimes
[i
].ContentType
);
706 if (package
->mimes
&& package
->loaded_mimes
> 0)
707 HeapFree(GetProcessHeap(),0,package
->mimes
);
709 for (i
= 0; i
< package
->loaded_appids
; i
++)
711 HeapFree(GetProcessHeap(),0,package
->appids
[i
].RemoteServerName
);
712 HeapFree(GetProcessHeap(),0,package
->appids
[i
].LocalServer
);
713 HeapFree(GetProcessHeap(),0,package
->appids
[i
].ServiceParameters
);
714 HeapFree(GetProcessHeap(),0,package
->appids
[i
].DllSurrogate
);
717 if (package
->appids
&& package
->loaded_appids
> 0)
718 HeapFree(GetProcessHeap(),0,package
->appids
);
722 for (i
= 0; i
< TOTAL_SCRIPTS
; i
++)
725 for (j
= 0; j
< package
->script
->ActionCount
[i
]; j
++)
726 HeapFree(GetProcessHeap(),0,package
->script
->Actions
[i
][j
]);
728 HeapFree(GetProcessHeap(),0,package
->script
->Actions
[i
]);
730 HeapFree(GetProcessHeap(),0,package
->script
);
733 HeapFree(GetProcessHeap(),0,package
->PackagePath
);
735 /* cleanup control event subscriptions */
736 ControlEvent_CleanupSubscriptions(package
);
739 static void ce_actiontext(MSIPACKAGE
* package
, LPCWSTR action
)
741 static const WCHAR szActionText
[] =
742 {'A','c','t','i','o','n','T','e','x','t',0};
745 row
= MSI_CreateRecord(1);
746 MSI_RecordSetStringW(row
,1,action
);
747 ControlEvent_FireSubscribedEvent(package
,szActionText
, row
);
748 msiobj_release(&row
->hdr
);
751 static void ui_progress(MSIPACKAGE
*package
, int a
, int b
, int c
, int d
)
755 row
= MSI_CreateRecord(4);
756 MSI_RecordSetInteger(row
,1,a
);
757 MSI_RecordSetInteger(row
,2,b
);
758 MSI_RecordSetInteger(row
,3,c
);
759 MSI_RecordSetInteger(row
,4,d
);
760 MSI_ProcessMessage(package
, INSTALLMESSAGE_PROGRESS
, row
);
761 msiobj_release(&row
->hdr
);
763 msi_dialog_check_messages(NULL
);
766 static void ui_actiondata(MSIPACKAGE
*package
, LPCWSTR action
, MSIRECORD
* record
)
768 static const WCHAR Query_t
[] =
769 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
770 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
771 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',
772 ' ','\'','%','s','\'',0};
776 static const WCHAR szActionData
[] =
777 {'A','c','t','i','o','n','D','a','t','a',0};
779 if (!package
->LastAction
|| strcmpW(package
->LastAction
,action
))
781 row
= MSI_QueryGetRecord(package
->db
, Query_t
, action
);
785 if (MSI_RecordIsNull(row
,3))
787 msiobj_release(&row
->hdr
);
791 /* update the cached actionformat */
792 HeapFree(GetProcessHeap(),0,package
->ActionFormat
);
793 package
->ActionFormat
= load_dynamic_stringW(row
,3);
795 HeapFree(GetProcessHeap(),0,package
->LastAction
);
796 package
->LastAction
= strdupW(action
);
798 msiobj_release(&row
->hdr
);
801 MSI_RecordSetStringW(record
,0,package
->ActionFormat
);
803 MSI_FormatRecordW(package
,record
,message
,&size
);
805 row
= MSI_CreateRecord(1);
806 MSI_RecordSetStringW(row
,1,message
);
808 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONDATA
, row
);
810 ControlEvent_FireSubscribedEvent(package
,szActionData
, row
);
812 msiobj_release(&row
->hdr
);
816 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
818 static const WCHAR template_s
[]=
819 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
821 static const WCHAR format
[] =
822 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
823 static const WCHAR Query_t
[] =
824 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
825 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
826 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
827 ' ','\'','%','s','\'',0};
833 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
835 row
= MSI_QueryGetRecord( package
->db
, Query_t
, action
);
839 ActionText
= MSI_RecordGetString(row
,2);
841 sprintfW(message
,template_s
,timet
,action
,ActionText
);
842 msiobj_release(&row
->hdr
);
844 row
= MSI_CreateRecord(1);
845 MSI_RecordSetStringW(row
,1,message
);
847 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
848 msiobj_release(&row
->hdr
);
851 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
855 static const WCHAR template_s
[]=
856 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
858 static const WCHAR template_e
[]=
859 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
860 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
862 static const WCHAR format
[] =
863 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
867 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
869 sprintfW(message
,template_s
,timet
,action
);
871 sprintfW(message
,template_e
,timet
,action
,rc
);
873 row
= MSI_CreateRecord(1);
874 MSI_RecordSetStringW(row
,1,message
);
876 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
877 msiobj_release(&row
->hdr
);
881 * build_directory_name()
883 * This function is to save messing round with directory names
884 * It handles adding backslashes between path segments,
885 * and can add \ at the end of the directory name if told to.
887 * It takes a variable number of arguments.
888 * It always allocates a new string for the result, so make sure
889 * to free the return value when finished with it.
891 * The first arg is the number of path segments that follow.
892 * The arguments following count are a list of path segments.
893 * A path segment may be NULL.
895 * Path segments will be added with a \ separating them.
896 * A \ will not be added after the last segment, however if the
897 * last segment is NULL, then the last character will be a \
900 static LPWSTR
build_directory_name(DWORD count
, ...)
907 for(i
=0; i
<count
; i
++)
909 LPCWSTR str
= va_arg(va
,LPCWSTR
);
911 sz
+= strlenW(str
) + 1;
915 dir
= HeapAlloc(GetProcessHeap(), 0, sz
*sizeof(WCHAR
));
919 for(i
=0; i
<count
; i
++)
921 LPCWSTR str
= va_arg(va
,LPCWSTR
);
925 if( ((i
+1)!=count
) && dir
[strlenW(dir
)-1]!='\\')
931 static BOOL
ACTION_VerifyComponentForAction(MSIPACKAGE
* package
, INT index
,
934 if (package
->components
[index
].Installed
== check
)
937 if (package
->components
[index
].ActionRequest
== check
)
943 static BOOL
ACTION_VerifyFeatureForAction(MSIPACKAGE
* package
, INT index
,
946 if (package
->features
[index
].Installed
== check
)
949 if (package
->features
[index
].ActionRequest
== check
)
956 /****************************************************
957 * TOP level entry points
958 *****************************************************/
960 UINT
ACTION_DoTopLevelINSTALL(MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
961 LPCWSTR szCommandLine
)
967 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
968 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
969 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
971 MSI_SetPropertyW(package
, szAction
, szInstall
);
973 package
->script
= HeapAlloc(GetProcessHeap(),0,sizeof(MSISCRIPT
));
974 memset(package
->script
,0,sizeof(MSISCRIPT
));
978 LPWSTR p
, check
, path
;
980 package
->PackagePath
= strdupW(szPackagePath
);
981 path
= strdupW(szPackagePath
);
982 p
= strrchrW(path
,'\\');
990 HeapFree(GetProcessHeap(),0,path
);
991 path
= HeapAlloc(GetProcessHeap(),0,MAX_PATH
*sizeof(WCHAR
));
992 GetCurrentDirectoryW(MAX_PATH
,path
);
996 check
= load_dynamic_property(package
, cszSourceDir
,NULL
);
998 MSI_SetPropertyW(package
, cszSourceDir
, path
);
1000 HeapFree(GetProcessHeap(), 0, check
);
1002 HeapFree(GetProcessHeap(), 0, path
);
1008 ptr
= (LPWSTR
)szCommandLine
;
1015 TRACE("Looking at %s\n",debugstr_w(ptr
));
1017 ptr2
= strchrW(ptr
,'=');
1023 while (*ptr
== ' ') ptr
++;
1025 prop
= HeapAlloc(GetProcessHeap(),0,(len
+1)*sizeof(WCHAR
));
1026 memcpy(prop
,ptr
,len
*sizeof(WCHAR
));
1032 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
1045 val
= HeapAlloc(GetProcessHeap(),0,(len
+1)*sizeof(WCHAR
));
1046 memcpy(val
,ptr2
,len
*sizeof(WCHAR
));
1049 if (strlenW(prop
) > 0)
1051 TRACE("Found commandline property (%s) = (%s)\n",
1052 debugstr_w(prop
), debugstr_w(val
));
1053 MSI_SetPropertyW(package
,prop
,val
);
1055 HeapFree(GetProcessHeap(),0,val
);
1056 HeapFree(GetProcessHeap(),0,prop
);
1063 if (MSI_GetPropertyW(package
,szUILevel
,buffer
,&sz
) == ERROR_SUCCESS
)
1065 if (atoiW(buffer
) >= INSTALLUILEVEL_REDUCED
)
1067 rc
= ACTION_ProcessUISequence(package
);
1069 if (rc
== ERROR_SUCCESS
)
1070 rc
= ACTION_ProcessExecSequence(package
,TRUE
);
1073 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
1076 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
1080 /* install was halted but should be considered a success */
1084 package
->script
->CurrentlyScripting
= FALSE
;
1086 /* process the ending type action */
1087 if (rc
== ERROR_SUCCESS
)
1088 ACTION_PerformActionSequence(package
,-1,ui
);
1089 else if (rc
== ERROR_INSTALL_USEREXIT
)
1090 ACTION_PerformActionSequence(package
,-2,ui
);
1091 else if (rc
== ERROR_INSTALL_SUSPEND
)
1092 ACTION_PerformActionSequence(package
,-4,ui
);
1094 ACTION_PerformActionSequence(package
,-3,ui
);
1096 /* finish up running custom actions */
1097 ACTION_FinishCustomActions(package
);
1102 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
, BOOL UI
)
1104 UINT rc
= ERROR_SUCCESS
;
1105 MSIRECORD
* row
= 0;
1106 static const WCHAR ExecSeqQuery
[] =
1107 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1108 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1109 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1110 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
1112 static const WCHAR UISeqQuery
[] =
1113 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1114 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
1115 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
1116 ' ', '=',' ','%','i',0};
1119 row
= MSI_QueryGetRecord(package
->db
, UISeqQuery
, seq
);
1121 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, seq
);
1125 LPCWSTR action
, cond
;
1127 TRACE("Running the actions\n");
1129 /* check conditions */
1130 cond
= MSI_RecordGetString(row
,2);
1133 /* this is a hack to skip errors in the condition code */
1134 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
1138 action
= MSI_RecordGetString(row
,1);
1141 ERR("failed to fetch action\n");
1142 rc
= ERROR_FUNCTION_FAILED
;
1147 rc
= ACTION_PerformUIAction(package
,action
);
1149 rc
= ACTION_PerformAction(package
,action
,FALSE
);
1151 msiobj_release(&row
->hdr
);
1159 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
1163 static const WCHAR ExecSeqQuery
[] =
1164 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1165 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1166 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1167 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
1168 'O','R','D','E','R',' ', 'B','Y',' ',
1169 '`','S','e','q','u','e','n','c','e','`',0 };
1170 MSIRECORD
* row
= 0;
1171 static const WCHAR IVQuery
[] =
1172 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
1173 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
1174 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
1175 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
1176 ' ','\'', 'I','n','s','t','a','l','l',
1177 'V','a','l','i','d','a','t','e','\'', 0};
1181 if (package
->script
->ExecuteSequenceRun
)
1183 TRACE("Execute Sequence already Run\n");
1184 return ERROR_SUCCESS
;
1187 package
->script
->ExecuteSequenceRun
= TRUE
;
1189 /* get the sequence number */
1192 row
= MSI_QueryGetRecord(package
->db
, IVQuery
);
1194 return ERROR_FUNCTION_FAILED
;
1195 seq
= MSI_RecordGetInteger(row
,1);
1196 msiobj_release(&row
->hdr
);
1199 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
1200 if (rc
== ERROR_SUCCESS
)
1202 rc
= MSI_ViewExecute(view
, 0);
1204 if (rc
!= ERROR_SUCCESS
)
1206 MSI_ViewClose(view
);
1207 msiobj_release(&view
->hdr
);
1211 TRACE("Running the actions\n");
1215 LPCWSTR cond
, action
;
1217 rc
= MSI_ViewFetch(view
,&row
);
1218 if (rc
!= ERROR_SUCCESS
)
1224 action
= MSI_RecordGetString(row
,1);
1227 rc
= ERROR_FUNCTION_FAILED
;
1228 msiobj_release(&row
->hdr
);
1232 /* check conditions */
1233 cond
= MSI_RecordGetString(row
,2);
1236 /* this is a hack to skip errors in the condition code */
1237 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
1239 msiobj_release(&row
->hdr
);
1240 TRACE("Skipping action: %s (condition is false)\n",
1241 debugstr_w(action
));
1246 rc
= ACTION_PerformAction(package
,action
,FALSE
);
1248 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
1251 if (rc
!= ERROR_SUCCESS
)
1253 ERR("Execution halted due to error (%i)\n",rc
);
1254 msiobj_release(&row
->hdr
);
1258 msiobj_release(&row
->hdr
);
1261 MSI_ViewClose(view
);
1262 msiobj_release(&view
->hdr
);
1270 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
1274 static const WCHAR ExecSeqQuery
[] =
1275 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1276 '`','I','n','s','t','a','l','l',
1277 'U','I','S','e','q','u','e','n','c','e','`',
1278 ' ','W','H','E','R','E',' ',
1279 '`','S','e','q','u','e','n','c','e','`',' ',
1280 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1281 '`','S','e','q','u','e','n','c','e','`',0};
1283 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1285 if (rc
== ERROR_SUCCESS
)
1287 rc
= MSI_ViewExecute(view
, 0);
1289 if (rc
!= ERROR_SUCCESS
)
1291 MSI_ViewClose(view
);
1292 msiobj_release(&view
->hdr
);
1296 TRACE("Running the actions \n");
1300 LPCWSTR action
, cond
;
1301 MSIRECORD
* row
= 0;
1303 rc
= MSI_ViewFetch(view
,&row
);
1304 if (rc
!= ERROR_SUCCESS
)
1310 action
= MSI_RecordGetString(row
,1);
1313 ERR("failed to fetch action\n");
1314 rc
= ERROR_FUNCTION_FAILED
;
1315 msiobj_release(&row
->hdr
);
1319 /* check conditions */
1320 cond
= MSI_RecordGetString(row
,2);
1323 /* this is a hack to skip errors in the condition code */
1324 if (MSI_EvaluateConditionW(package
,cond
) == MSICONDITION_FALSE
)
1326 msiobj_release(&row
->hdr
);
1327 TRACE("Skipping action: %s (condition is false)\n",
1328 debugstr_w(action
));
1333 rc
= ACTION_PerformUIAction(package
,action
);
1335 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
1338 if (rc
!= ERROR_SUCCESS
)
1340 ERR("Execution halted due to error (%i)\n",rc
);
1341 msiobj_release(&row
->hdr
);
1345 msiobj_release(&row
->hdr
);
1348 MSI_ViewClose(view
);
1349 msiobj_release(&view
->hdr
);
1356 /********************************************************
1357 * ACTION helper functions and functions that perform the actions
1358 *******************************************************/
1359 static BOOL
ACTION_HandleStandardAction(MSIPACKAGE
*package
, LPCWSTR action
,
1360 UINT
* rc
, BOOL force
)
1366 if (!run
&& !package
->script
->CurrentlyScripting
)
1371 if (strcmpW(action
,szInstallFinalize
) == 0 ||
1372 strcmpW(action
,szInstallExecute
) == 0 ||
1373 strcmpW(action
,szInstallExecuteAgain
) == 0)
1378 while (StandardActions
[i
].action
!= NULL
)
1380 if (strcmpW(StandardActions
[i
].action
, action
)==0)
1382 ce_actiontext(package
, action
);
1385 ui_actioninfo(package
, action
, TRUE
, 0);
1386 *rc
= schedule_action(package
,INSTALL_SCRIPT
,action
);
1387 ui_actioninfo(package
, action
, FALSE
, *rc
);
1391 ui_actionstart(package
, action
);
1392 if (StandardActions
[i
].handler
)
1394 *rc
= StandardActions
[i
].handler(package
);
1398 FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action
));
1399 *rc
= ERROR_SUCCESS
;
1410 static BOOL
ACTION_HandleDialogBox( MSIPACKAGE
*package
, LPCWSTR dialog
, UINT
* rc
)
1414 if (ACTION_DialogBox(package
,dialog
) == ERROR_SUCCESS
)
1416 *rc
= package
->CurrentInstallState
;
1422 static BOOL
ACTION_HandleCustomAction( MSIPACKAGE
* package
, LPCWSTR action
,
1423 UINT
* rc
, BOOL force
)
1428 arc
= ACTION_CustomAction(package
,action
, force
);
1430 if (arc
!= ERROR_CALL_NOT_IMPLEMENTED
)
1439 * A lot of actions are really important even if they don't do anything
1440 * explicit... Lots of properties are set at the beginning of the installation
1441 * CostFinalize does a bunch of work to translate the directories and such
1443 * But until I get write access to the database that is hard, so I am going to
1444 * hack it to see if I can get something to run.
1446 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
, BOOL force
)
1448 UINT rc
= ERROR_SUCCESS
;
1451 TRACE("Performing action (%s)\n",debugstr_w(action
));
1453 handled
= ACTION_HandleStandardAction(package
, action
, &rc
, force
);
1456 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, force
);
1460 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action
));
1461 rc
= ERROR_FUNCTION_NOT_CALLED
;
1464 package
->CurrentInstallState
= rc
;
1468 UINT
ACTION_PerformUIAction(MSIPACKAGE
*package
, const WCHAR
*action
)
1470 UINT rc
= ERROR_SUCCESS
;
1471 BOOL handled
= FALSE
;
1473 TRACE("Performing action (%s)\n",debugstr_w(action
));
1475 handled
= ACTION_HandleStandardAction(package
, action
, &rc
,TRUE
);
1478 handled
= ACTION_HandleCustomAction(package
, action
, &rc
, FALSE
);
1481 handled
= ACTION_HandleDialogBox(package
, action
, &rc
);
1483 msi_dialog_check_messages( NULL
);
1487 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action
));
1488 rc
= ERROR_FUNCTION_NOT_CALLED
;
1491 package
->CurrentInstallState
= rc
;
1495 /***********************************************************************
1498 * Recursively create all directories in the path.
1500 * shamelessly stolen from setupapi/queue.c
1502 static BOOL
create_full_pathW(const WCHAR
*path
)
1508 new_path
= HeapAlloc(GetProcessHeap(), 0, (strlenW(path
) + 1) *
1511 strcpyW(new_path
, path
);
1513 while((len
= strlenW(new_path
)) && new_path
[len
- 1] == '\\')
1514 new_path
[len
- 1] = 0;
1516 while(!CreateDirectoryW(new_path
, NULL
))
1519 DWORD last_error
= GetLastError();
1520 if(last_error
== ERROR_ALREADY_EXISTS
)
1523 if(last_error
!= ERROR_PATH_NOT_FOUND
)
1529 if(!(slash
= strrchrW(new_path
, '\\')))
1535 len
= slash
- new_path
;
1537 if(!create_full_pathW(new_path
))
1542 new_path
[len
] = '\\';
1545 HeapFree(GetProcessHeap(), 0, new_path
);
1550 * Also we cannot enable/disable components either, so for now I am just going
1551 * to do all the directories for all the components.
1553 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1555 static const WCHAR ExecSeqQuery
[] =
1556 {'S','E','L','E','C','T',' ',
1557 '`','D','i','r','e','c','t','o','r','y','_','`',
1558 ' ','F','R','O','M',' ',
1559 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1564 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1565 if (rc
!= ERROR_SUCCESS
)
1566 return ERROR_SUCCESS
;
1568 rc
= MSI_ViewExecute(view
, 0);
1569 if (rc
!= ERROR_SUCCESS
)
1571 MSI_ViewClose(view
);
1572 msiobj_release(&view
->hdr
);
1580 MSIRECORD
*row
= NULL
, *uirow
;
1582 rc
= MSI_ViewFetch(view
,&row
);
1583 if (rc
!= ERROR_SUCCESS
)
1589 dir
= MSI_RecordGetString(row
,1);
1592 ERR("Unable to get folder id \n");
1593 msiobj_release(&row
->hdr
);
1597 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,&folder
);
1600 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
1601 msiobj_release(&row
->hdr
);
1605 TRACE("Folder is %s\n",debugstr_w(full_path
));
1608 uirow
= MSI_CreateRecord(1);
1609 MSI_RecordSetStringW(uirow
,1,full_path
);
1610 ui_actiondata(package
,szCreateFolders
,uirow
);
1611 msiobj_release( &uirow
->hdr
);
1613 if (folder
->State
== 0)
1614 create_full_pathW(full_path
);
1618 msiobj_release(&row
->hdr
);
1619 HeapFree(GetProcessHeap(),0,full_path
);
1621 MSI_ViewClose(view
);
1622 msiobj_release(&view
->hdr
);
1627 static int load_component(MSIPACKAGE
* package
, MSIRECORD
* row
)
1629 int index
= package
->loaded_components
;
1632 /* fill in the data */
1634 package
->loaded_components
++;
1635 if (package
->loaded_components
== 1)
1636 package
->components
= HeapAlloc(GetProcessHeap(),0,
1637 sizeof(MSICOMPONENT
));
1639 package
->components
= HeapReAlloc(GetProcessHeap(),0,
1640 package
->components
, package
->loaded_components
*
1641 sizeof(MSICOMPONENT
));
1643 memset(&package
->components
[index
],0,sizeof(MSICOMPONENT
));
1645 sz
= IDENTIFIER_SIZE
;
1646 MSI_RecordGetStringW(row
,1,package
->components
[index
].Component
,&sz
);
1648 TRACE("Loading Component %s\n",
1649 debugstr_w(package
->components
[index
].Component
));
1652 if (!MSI_RecordIsNull(row
,2))
1653 MSI_RecordGetStringW(row
,2,package
->components
[index
].ComponentId
,&sz
);
1655 sz
= IDENTIFIER_SIZE
;
1656 MSI_RecordGetStringW(row
,3,package
->components
[index
].Directory
,&sz
);
1658 package
->components
[index
].Attributes
= MSI_RecordGetInteger(row
,4);
1661 MSI_RecordGetStringW(row
,5,package
->components
[index
].Condition
,&sz
);
1663 sz
= IDENTIFIER_SIZE
;
1664 MSI_RecordGetStringW(row
,6,package
->components
[index
].KeyPath
,&sz
);
1666 package
->components
[index
].Installed
= INSTALLSTATE_ABSENT
;
1667 package
->components
[index
].Action
= INSTALLSTATE_UNKNOWN
;
1668 package
->components
[index
].ActionRequest
= INSTALLSTATE_UNKNOWN
;
1670 package
->components
[index
].Enabled
= TRUE
;
1675 static void load_feature(MSIPACKAGE
* package
, MSIRECORD
* row
)
1677 int index
= package
->loaded_features
;
1679 static const WCHAR Query1
[] =
1680 {'S','E','L','E','C','T',' ',
1681 '`','C','o','m','p','o','n','e','n','t','_','`',
1682 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1683 'C','o','m','p','o','n','e','n','t','s','`',' ',
1684 'W','H','E','R','E',' ',
1685 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1686 static const WCHAR Query2
[] =
1687 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1688 '`','C','o','m','p','o','n','e','n','t','`',' ',
1689 'W','H','E','R','E',' ',
1690 '`','C','o','m','p','o','n','e','n','t','`',' ',
1691 '=','\'','%','s','\'',0};
1698 /* fill in the data */
1700 package
->loaded_features
++;
1701 if (package
->loaded_features
== 1)
1702 package
->features
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE
));
1704 package
->features
= HeapReAlloc(GetProcessHeap(),0,package
->features
,
1705 package
->loaded_features
* sizeof(MSIFEATURE
));
1707 memset(&package
->features
[index
],0,sizeof(MSIFEATURE
));
1709 sz
= IDENTIFIER_SIZE
;
1710 MSI_RecordGetStringW(row
,1,package
->features
[index
].Feature
,&sz
);
1712 TRACE("Loading feature %s\n",debugstr_w(package
->features
[index
].Feature
));
1714 sz
= IDENTIFIER_SIZE
;
1715 if (!MSI_RecordIsNull(row
,2))
1716 MSI_RecordGetStringW(row
,2,package
->features
[index
].Feature_Parent
,&sz
);
1719 if (!MSI_RecordIsNull(row
,3))
1720 MSI_RecordGetStringW(row
,3,package
->features
[index
].Title
,&sz
);
1723 if (!MSI_RecordIsNull(row
,4))
1724 MSI_RecordGetStringW(row
,4,package
->features
[index
].Description
,&sz
);
1726 if (!MSI_RecordIsNull(row
,5))
1727 package
->features
[index
].Display
= MSI_RecordGetInteger(row
,5);
1729 package
->features
[index
].Level
= MSI_RecordGetInteger(row
,6);
1731 sz
= IDENTIFIER_SIZE
;
1732 if (!MSI_RecordIsNull(row
,7))
1733 MSI_RecordGetStringW(row
,7,package
->features
[index
].Directory
,&sz
);
1735 package
->features
[index
].Attributes
= MSI_RecordGetInteger(row
,8);
1737 package
->features
[index
].Installed
= INSTALLSTATE_ABSENT
;
1738 package
->features
[index
].Action
= INSTALLSTATE_UNKNOWN
;
1739 package
->features
[index
].ActionRequest
= INSTALLSTATE_UNKNOWN
;
1741 /* load feature components */
1743 rc
= MSI_OpenQuery(package
->db
, &view
, Query1
, package
->features
[index
].Feature
);
1744 if (rc
!= ERROR_SUCCESS
)
1746 rc
= MSI_ViewExecute(view
,0);
1747 if (rc
!= ERROR_SUCCESS
)
1749 MSI_ViewClose(view
);
1750 msiobj_release(&view
->hdr
);
1758 INT cnt
= package
->features
[index
].ComponentCount
;
1760 rc
= MSI_ViewFetch(view
,&row2
);
1761 if (rc
!= ERROR_SUCCESS
)
1764 component
= MSI_RecordGetString(row2
,1);
1766 /* check to see if the component is already loaded */
1767 c_indx
= get_loaded_component(package
,component
);
1770 TRACE("Component %s already loaded at %i\n", debugstr_w(component
),
1772 package
->features
[index
].Components
[cnt
] = c_indx
;
1773 package
->features
[index
].ComponentCount
++;
1774 msiobj_release( &row2
->hdr
);
1778 rc
= MSI_OpenQuery(package
->db
, &view2
, Query2
, component
);
1779 if (rc
!= ERROR_SUCCESS
)
1781 msiobj_release( &row2
->hdr
);
1784 rc
= MSI_ViewExecute(view2
,0);
1785 if (rc
!= ERROR_SUCCESS
)
1787 msiobj_release( &row2
->hdr
);
1788 MSI_ViewClose(view2
);
1789 msiobj_release( &view2
->hdr
);
1796 rc
= MSI_ViewFetch(view2
,&row3
);
1797 if (rc
!= ERROR_SUCCESS
)
1799 c_indx
= load_component(package
,row3
);
1800 msiobj_release( &row3
->hdr
);
1802 package
->features
[index
].Components
[cnt
] = c_indx
;
1803 package
->features
[index
].ComponentCount
++;
1804 TRACE("Loaded new component to index %i\n",c_indx
);
1806 MSI_ViewClose(view2
);
1807 msiobj_release( &view2
->hdr
);
1808 msiobj_release( &row2
->hdr
);
1810 MSI_ViewClose(view
);
1811 msiobj_release(&view
->hdr
);
1814 static UINT
load_file(MSIPACKAGE
* package
, MSIRECORD
* row
)
1816 DWORD index
= package
->loaded_files
;
1820 /* fill in the data */
1822 package
->loaded_files
++;
1823 if (package
->loaded_files
== 1)
1824 package
->files
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE
));
1826 package
->files
= HeapReAlloc(GetProcessHeap(),0,
1827 package
->files
, package
->loaded_files
* sizeof(MSIFILE
));
1829 memset(&package
->files
[index
],0,sizeof(MSIFILE
));
1831 package
->files
[index
].File
= load_dynamic_stringW(row
, 1);
1832 buffer
= load_dynamic_stringW(row
, 2);
1834 package
->files
[index
].ComponentIndex
= -1;
1835 for (i
= 0; i
< package
->loaded_components
; i
++)
1836 if (strcmpW(package
->components
[i
].Component
,buffer
)==0)
1838 package
->files
[index
].ComponentIndex
= i
;
1841 if (package
->files
[index
].ComponentIndex
== -1)
1842 ERR("Unfound Component %s\n",debugstr_w(buffer
));
1843 HeapFree(GetProcessHeap(), 0, buffer
);
1845 package
->files
[index
].FileName
= load_dynamic_stringW(row
,3);
1846 reduce_to_longfilename(package
->files
[index
].FileName
);
1848 package
->files
[index
].ShortName
= load_dynamic_stringW(row
,3);
1849 reduce_to_shortfilename(package
->files
[index
].ShortName
);
1851 package
->files
[index
].FileSize
= MSI_RecordGetInteger(row
,4);
1852 package
->files
[index
].Version
= load_dynamic_stringW(row
, 5);
1853 package
->files
[index
].Language
= load_dynamic_stringW(row
, 6);
1854 package
->files
[index
].Attributes
= MSI_RecordGetInteger(row
,7);
1855 package
->files
[index
].Sequence
= MSI_RecordGetInteger(row
,8);
1857 package
->files
[index
].Temporary
= FALSE
;
1858 package
->files
[index
].State
= 0;
1860 TRACE("File Loaded (%s)\n",debugstr_w(package
->files
[index
].File
));
1862 return ERROR_SUCCESS
;
1865 static UINT
load_all_files(MSIPACKAGE
*package
)
1870 static const WCHAR Query
[] =
1871 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1872 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1873 '`','S','e','q','u','e','n','c','e','`', 0};
1876 return ERROR_INVALID_HANDLE
;
1878 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1879 if (rc
!= ERROR_SUCCESS
)
1880 return ERROR_SUCCESS
;
1882 rc
= MSI_ViewExecute(view
, 0);
1883 if (rc
!= ERROR_SUCCESS
)
1885 MSI_ViewClose(view
);
1886 msiobj_release(&view
->hdr
);
1887 return ERROR_SUCCESS
;
1892 rc
= MSI_ViewFetch(view
,&row
);
1893 if (rc
!= ERROR_SUCCESS
)
1898 load_file(package
,row
);
1899 msiobj_release(&row
->hdr
);
1901 MSI_ViewClose(view
);
1902 msiobj_release(&view
->hdr
);
1904 return ERROR_SUCCESS
;
1909 * I am not doing any of the costing functionality yet.
1910 * Mostly looking at doing the Component and Feature loading
1912 * The native MSI does A LOT of modification to tables here. Mostly adding
1913 * a lot of temporary columns to the Feature and Component tables.
1915 * note: Native msi also tracks the short filename. But I am only going to
1916 * track the long ones. Also looking at this directory table
1917 * it appears that the directory table does not get the parents
1918 * resolved base on property only based on their entries in the
1921 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1926 static const WCHAR Query_all
[] =
1927 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1928 '`','F','e','a','t','u','r','e','`',0};
1929 static const WCHAR szCosting
[] =
1930 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1931 static const WCHAR szZero
[] = { '0', 0 };
1935 MSI_GetPropertyW(package
, szCosting
, buffer
, &sz
);
1937 return ERROR_SUCCESS
;
1939 MSI_SetPropertyW(package
, szCosting
, szZero
);
1940 MSI_SetPropertyW(package
, cszRootDrive
, c_colon
);
1942 rc
= MSI_DatabaseOpenViewW(package
->db
,Query_all
,&view
);
1943 if (rc
!= ERROR_SUCCESS
)
1945 rc
= MSI_ViewExecute(view
,0);
1946 if (rc
!= ERROR_SUCCESS
)
1948 MSI_ViewClose(view
);
1949 msiobj_release(&view
->hdr
);
1956 rc
= MSI_ViewFetch(view
,&row
);
1957 if (rc
!= ERROR_SUCCESS
)
1960 load_feature(package
,row
);
1961 msiobj_release(&row
->hdr
);
1963 MSI_ViewClose(view
);
1964 msiobj_release(&view
->hdr
);
1966 load_all_files(package
);
1968 return ERROR_SUCCESS
;
1971 UINT
schedule_action(MSIPACKAGE
*package
, UINT script
, LPCWSTR action
)
1974 LPWSTR
*newbuf
= NULL
;
1975 if (script
>= TOTAL_SCRIPTS
)
1977 FIXME("Unknown script requested %i\n",script
);
1978 return ERROR_FUNCTION_FAILED
;
1980 TRACE("Scheduling Action %s in script %i\n",debugstr_w(action
), script
);
1982 count
= package
->script
->ActionCount
[script
];
1983 package
->script
->ActionCount
[script
]++;
1985 newbuf
= HeapReAlloc(GetProcessHeap(),0,
1986 package
->script
->Actions
[script
],
1987 package
->script
->ActionCount
[script
]* sizeof(LPWSTR
));
1989 newbuf
= HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR
));
1991 newbuf
[count
] = strdupW(action
);
1992 package
->script
->Actions
[script
] = newbuf
;
1994 return ERROR_SUCCESS
;
1997 static UINT
execute_script(MSIPACKAGE
*package
, UINT script
)
2000 UINT rc
= ERROR_SUCCESS
;
2002 TRACE("Executing Script %i\n",script
);
2004 for (i
= 0; i
< package
->script
->ActionCount
[script
]; i
++)
2007 action
= package
->script
->Actions
[script
][i
];
2008 ui_actionstart(package
, action
);
2009 TRACE("Executing Action (%s)\n",debugstr_w(action
));
2010 rc
= ACTION_PerformAction(package
, action
, TRUE
);
2011 HeapFree(GetProcessHeap(),0,package
->script
->Actions
[script
][i
]);
2012 if (rc
!= ERROR_SUCCESS
)
2015 HeapFree(GetProcessHeap(),0,package
->script
->Actions
[script
]);
2017 package
->script
->ActionCount
[script
] = 0;
2018 package
->script
->Actions
[script
] = NULL
;
2022 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
2024 return ERROR_SUCCESS
;
2028 static INT
load_folder(MSIPACKAGE
*package
, const WCHAR
* dir
)
2030 static const WCHAR Query
[] =
2031 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2032 '`','D','i','r','e','c', 't','o','r','y','`',' ',
2033 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
2034 ' ','=',' ','\'','%','s','\'',
2036 LPWSTR ptargetdir
, targetdir
, parent
, srcdir
;
2037 LPWSTR shortname
= NULL
;
2038 MSIRECORD
* row
= 0;
2042 TRACE("Looking for dir %s\n",debugstr_w(dir
));
2044 for (i
= 0; i
< package
->loaded_folders
; i
++)
2046 if (strcmpW(package
->folders
[i
].Directory
,dir
)==0)
2048 TRACE(" %s retuning on index %lu\n",debugstr_w(dir
),i
);
2053 TRACE("Working to load %s\n",debugstr_w(dir
));
2055 index
= package
->loaded_folders
++;
2056 if (package
->loaded_folders
==1)
2057 package
->folders
= HeapAlloc(GetProcessHeap(),0,
2060 package
->folders
= HeapReAlloc(GetProcessHeap(),0,
2061 package
->folders
, package
->loaded_folders
*
2064 memset(&package
->folders
[index
],0,sizeof(MSIFOLDER
));
2066 package
->folders
[index
].Directory
= strdupW(dir
);
2068 row
= MSI_QueryGetRecord(package
->db
, Query
, dir
);
2072 ptargetdir
= targetdir
= load_dynamic_stringW(row
,3);
2074 /* split src and target dir */
2075 if (strchrW(targetdir
,':'))
2077 srcdir
=strchrW(targetdir
,':');
2084 /* for now only pick long filename versions */
2085 if (strchrW(targetdir
,'|'))
2087 shortname
= targetdir
;
2088 targetdir
= strchrW(targetdir
,'|');
2092 /* for the sourcedir pick the short filename */
2093 if (srcdir
&& strchrW(srcdir
,'|'))
2095 LPWSTR p
= strchrW(srcdir
,'|');
2099 /* now check for root dirs */
2100 if (targetdir
[0] == '.' && targetdir
[1] == 0)
2103 if (srcdir
&& srcdir
[0] == '.' && srcdir
[1] == 0)
2108 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir
));
2109 HeapFree(GetProcessHeap(),0, package
->folders
[index
].TargetDefault
);
2110 package
->folders
[index
].TargetDefault
= strdupW(targetdir
);
2114 package
->folders
[index
].SourceDefault
= strdupW(srcdir
);
2116 package
->folders
[index
].SourceDefault
= strdupW(shortname
);
2118 package
->folders
[index
].SourceDefault
= strdupW(targetdir
);
2119 HeapFree(GetProcessHeap(), 0, ptargetdir
);
2120 TRACE(" SourceDefault = %s\n",debugstr_w(package
->folders
[index
].SourceDefault
));
2122 parent
= load_dynamic_stringW(row
,2);
2125 i
= load_folder(package
,parent
);
2126 package
->folders
[index
].ParentIndex
= i
;
2127 TRACE("Parent is index %i... %s %s\n",
2128 package
->folders
[index
].ParentIndex
,
2129 debugstr_w(package
->folders
[package
->folders
[index
].ParentIndex
].Directory
),
2130 debugstr_w(parent
));
2133 package
->folders
[index
].ParentIndex
= -2;
2134 HeapFree(GetProcessHeap(), 0, parent
);
2136 package
->folders
[index
].Property
= load_dynamic_property(package
, dir
,NULL
);
2138 msiobj_release(&row
->hdr
);
2139 TRACE(" %s retuning on index %i\n",debugstr_w(dir
),index
);
2144 LPWSTR
resolve_folder(MSIPACKAGE
*package
, LPCWSTR name
, BOOL source
,
2145 BOOL set_prop
, MSIFOLDER
**folder
)
2148 LPWSTR p
, path
= NULL
;
2150 TRACE("Working to resolve %s\n",debugstr_w(name
));
2152 /* special resolving for Target and Source root dir */
2153 if (strcmpW(name
,cszTargetDir
)==0 || strcmpW(name
,cszSourceDir
)==0)
2157 path
= load_dynamic_property(package
,cszTargetDir
,NULL
);
2160 path
= load_dynamic_property(package
,cszRootDrive
,NULL
);
2162 MSI_SetPropertyW(package
,cszTargetDir
,path
);
2166 for (i
= 0; i
< package
->loaded_folders
; i
++)
2168 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
2171 *folder
= &(package
->folders
[i
]);
2177 path
= load_dynamic_property(package
,cszSourceDir
,NULL
);
2180 path
= load_dynamic_property(package
,cszDatabase
,NULL
);
2183 p
= strrchrW(path
,'\\');
2190 for (i
= 0; i
< package
->loaded_folders
; i
++)
2192 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
2195 *folder
= &(package
->folders
[i
]);
2201 for (i
= 0; i
< package
->loaded_folders
; i
++)
2203 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
2207 if (i
>= package
->loaded_folders
)
2211 *folder
= &(package
->folders
[i
]);
2213 if (!source
&& package
->folders
[i
].ResolvedTarget
)
2215 path
= strdupW(package
->folders
[i
].ResolvedTarget
);
2216 TRACE(" already resolved to %s\n",debugstr_w(path
));
2219 else if (source
&& package
->folders
[i
].ResolvedSource
)
2221 path
= strdupW(package
->folders
[i
].ResolvedSource
);
2222 TRACE(" (source)already resolved to %s\n",debugstr_w(path
));
2225 else if (!source
&& package
->folders
[i
].Property
)
2227 path
= build_directory_name(2, package
->folders
[i
].Property
, NULL
);
2229 TRACE(" internally set to %s\n",debugstr_w(path
));
2231 MSI_SetPropertyW(package
,name
,path
);
2235 if (package
->folders
[i
].ParentIndex
>= 0)
2237 LPWSTR parent
= package
->folders
[package
->folders
[i
].ParentIndex
].Directory
;
2239 TRACE(" ! Parent is %s\n", debugstr_w(parent
));
2241 p
= resolve_folder(package
, parent
, source
, set_prop
, NULL
);
2244 TRACE(" TargetDefault = %s\n",debugstr_w(package
->folders
[i
].TargetDefault
));
2245 path
= build_directory_name(3, p
, package
->folders
[i
].TargetDefault
, NULL
);
2246 package
->folders
[i
].ResolvedTarget
= strdupW(path
);
2247 TRACE(" resolved into %s\n",debugstr_w(path
));
2249 MSI_SetPropertyW(package
,name
,path
);
2253 path
= build_directory_name(3, p
, package
->folders
[i
].SourceDefault
, NULL
);
2254 TRACE(" (source)resolved into %s\n",debugstr_w(path
));
2255 package
->folders
[i
].ResolvedSource
= strdupW(path
);
2257 HeapFree(GetProcessHeap(),0,p
);
2262 /* scan for and update current install states */
2263 static void ACTION_UpdateInstallStates(MSIPACKAGE
*package
)
2268 productcode
= load_dynamic_property(package
,szProductCode
,NULL
);
2270 for (i
= 0; i
< package
->loaded_components
; i
++)
2273 res
= MsiGetComponentPathW(productcode
,
2274 package
->components
[i
].ComponentId
, NULL
, NULL
);
2276 res
= INSTALLSTATE_ABSENT
;
2277 package
->components
[i
].Installed
= res
;
2280 for (i
= 0; i
< package
->loaded_features
; i
++)
2282 INSTALLSTATE res
= -10;
2284 for (j
= 0; j
< package
->features
[i
].ComponentCount
; j
++)
2286 MSICOMPONENT
* component
= &package
->components
[package
->features
[i
].
2289 res
= component
->Installed
;
2292 if (res
== component
->Installed
)
2295 if (res
!= component
->Installed
)
2296 res
= INSTALLSTATE_INCOMPLETE
;
2302 /* update compoennt state based on a feature change */
2303 void ACTION_UpdateComponentStates(MSIPACKAGE
*package
, LPCWSTR szFeature
)
2306 INSTALLSTATE newstate
;
2307 MSIFEATURE
*feature
;
2309 i
= get_loaded_feature(package
,szFeature
);
2313 feature
= &package
->features
[i
];
2314 newstate
= feature
->ActionRequest
;
2316 for( i
= 0; i
< feature
->ComponentCount
; i
++)
2318 MSICOMPONENT
* component
= &package
->components
[feature
->Components
[i
]];
2320 TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n",
2321 newstate
, debugstr_w(component
->Component
), component
->Installed
,
2322 component
->Action
, component
->ActionRequest
);
2324 if (!component
->Enabled
)
2328 if (newstate
== INSTALLSTATE_LOCAL
)
2330 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
2331 component
->Action
= INSTALLSTATE_LOCAL
;
2337 component
->ActionRequest
= newstate
;
2338 component
->Action
= newstate
;
2340 /*if any other feature wants is local we need to set it local*/
2342 j
< package
->loaded_features
&&
2343 component
->ActionRequest
!= INSTALLSTATE_LOCAL
;
2346 for (k
= 0; k
< package
->features
[j
].ComponentCount
; k
++)
2347 if ( package
->features
[j
].Components
[k
] ==
2348 feature
->Components
[i
] )
2350 if (package
->features
[j
].ActionRequest
==
2353 TRACE("Saved by %s\n", debugstr_w(package
->features
[j
].Feature
));
2354 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
2355 component
->Action
= INSTALLSTATE_LOCAL
;
2362 TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n",
2363 newstate
, debugstr_w(component
->Component
), component
->Installed
,
2364 component
->Action
, component
->ActionRequest
);
2368 static BOOL
process_state_property (MSIPACKAGE
* package
, LPCWSTR property
,
2371 static const WCHAR all
[]={'A','L','L',0};
2372 LPWSTR override
= NULL
;
2376 override
= load_dynamic_property(package
, property
, NULL
);
2380 for(i
= 0; i
< package
->loaded_features
; i
++)
2382 if (strcmpiW(override
,all
)==0)
2384 package
->features
[i
].ActionRequest
= state
;
2385 package
->features
[i
].Action
= state
;
2389 LPWSTR ptr
= override
;
2390 LPWSTR ptr2
= strchrW(override
,',');
2395 strncmpW(ptr
,package
->features
[i
].Feature
, ptr2
-ptr
)==0)
2397 strcmpW(ptr
,package
->features
[i
].Feature
)==0))
2399 package
->features
[i
].ActionRequest
= state
;
2400 package
->features
[i
].Action
= state
;
2406 ptr2
= strchrW(ptr
,',');
2413 HeapFree(GetProcessHeap(),0,override
);
2419 static UINT
SetFeatureStates(MSIPACKAGE
*package
)
2425 static const WCHAR szlevel
[] =
2426 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2427 static const WCHAR szAddLocal
[] =
2428 {'A','D','D','L','O','C','A','L',0};
2429 static const WCHAR szRemove
[] =
2430 {'R','E','M','O','V','E',0};
2431 BOOL override
= FALSE
;
2433 /* I do not know if this is where it should happen.. but */
2435 TRACE("Checking Install Level\n");
2437 level
= load_dynamic_property(package
,szlevel
,NULL
);
2440 install_level
= atoiW(level
);
2441 HeapFree(GetProcessHeap(), 0, level
);
2446 /* ok hereis the _real_ rub
2447 * all these activation/deactivation things happen in order and things
2448 * later on the list override things earlier on the list.
2449 * 1) INSTALLLEVEL processing
2459 * 11) FILEADDDEFAULT
2460 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
2461 * ignored for all the features. seems strange, especially since it is not
2462 * documented anywhere, but it is how it works.
2464 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
2465 * REMOVE are the big ones, since we don't handle administrative installs
2468 override
|= process_state_property(package
,szAddLocal
,INSTALLSTATE_LOCAL
);
2469 override
|= process_state_property(package
,szRemove
,INSTALLSTATE_ABSENT
);
2473 for(i
= 0; i
< package
->loaded_features
; i
++)
2475 BOOL feature_state
= ((package
->features
[i
].Level
> 0) &&
2476 (package
->features
[i
].Level
<= install_level
));
2478 if ((feature_state
) &&
2479 (package
->features
[i
].Action
== INSTALLSTATE_UNKNOWN
))
2481 if (package
->features
[i
].Attributes
&
2482 msidbFeatureAttributesFavorSource
)
2484 package
->features
[i
].ActionRequest
= INSTALLSTATE_SOURCE
;
2485 package
->features
[i
].Action
= INSTALLSTATE_SOURCE
;
2487 else if (package
->features
[i
].Attributes
&
2488 msidbFeatureAttributesFavorAdvertise
)
2490 package
->features
[i
].ActionRequest
=INSTALLSTATE_ADVERTISED
;
2491 package
->features
[i
].Action
=INSTALLSTATE_ADVERTISED
;
2495 package
->features
[i
].ActionRequest
= INSTALLSTATE_LOCAL
;
2496 package
->features
[i
].Action
= INSTALLSTATE_LOCAL
;
2503 /* set the Preselected Property */
2504 static const WCHAR szPreselected
[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
2505 static const WCHAR szOne
[] = { '1', 0 };
2507 MSI_SetPropertyW(package
,szPreselected
,szOne
);
2511 * now we want to enable or disable components base on feature
2514 for(i
= 0; i
< package
->loaded_features
; i
++)
2516 MSIFEATURE
* feature
= &package
->features
[i
];
2517 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
2518 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
2519 feature
->ActionRequest
);
2521 for( j
= 0; j
< feature
->ComponentCount
; j
++)
2523 MSICOMPONENT
* component
= &package
->components
[
2524 feature
->Components
[j
]];
2526 if (!component
->Enabled
)
2528 component
->Action
= INSTALLSTATE_UNKNOWN
;
2529 component
->ActionRequest
= INSTALLSTATE_UNKNOWN
;
2533 if (feature
->Action
== INSTALLSTATE_LOCAL
)
2535 component
->Action
= INSTALLSTATE_LOCAL
;
2536 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
2538 else if (feature
->ActionRequest
== INSTALLSTATE_SOURCE
)
2540 if ((component
->Action
== INSTALLSTATE_UNKNOWN
) ||
2541 (component
->Action
== INSTALLSTATE_ABSENT
) ||
2542 (component
->Action
== INSTALLSTATE_ADVERTISED
))
2545 component
->Action
= INSTALLSTATE_SOURCE
;
2546 component
->ActionRequest
= INSTALLSTATE_SOURCE
;
2549 else if (feature
->ActionRequest
== INSTALLSTATE_ADVERTISED
)
2551 if ((component
->Action
== INSTALLSTATE_UNKNOWN
) ||
2552 (component
->Action
== INSTALLSTATE_ABSENT
))
2555 component
->Action
= INSTALLSTATE_ADVERTISED
;
2556 component
->ActionRequest
= INSTALLSTATE_ADVERTISED
;
2559 else if (feature
->ActionRequest
== INSTALLSTATE_ABSENT
)
2561 if (component
->Action
== INSTALLSTATE_UNKNOWN
)
2563 component
->Action
= INSTALLSTATE_ABSENT
;
2564 component
->ActionRequest
= INSTALLSTATE_ABSENT
;
2571 for(i
= 0; i
< package
->loaded_components
; i
++)
2573 MSICOMPONENT
* component
= &package
->components
[i
];
2575 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
2576 debugstr_w(component
->Component
), component
->Installed
,
2577 component
->Action
, component
->ActionRequest
);
2581 return ERROR_SUCCESS
;
2585 * A lot is done in this function aside from just the costing.
2586 * The costing needs to be implemented at some point but for now I am going
2587 * to focus on the directory building
2590 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
2592 static const WCHAR ExecSeqQuery
[] =
2593 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2594 '`','D','i','r','e','c','t','o','r','y','`',0};
2595 static const WCHAR ConditionQuery
[] =
2596 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2597 '`','C','o','n','d','i','t','i','o','n','`',0};
2598 static const WCHAR szCosting
[] =
2599 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2600 static const WCHAR szlevel
[] =
2601 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2602 static const WCHAR szOne
[] = { '1', 0 };
2610 MSI_GetPropertyW(package
, szCosting
, buffer
, &sz
);
2612 return ERROR_SUCCESS
;
2614 TRACE("Building Directory properties\n");
2616 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2617 if (rc
== ERROR_SUCCESS
)
2619 rc
= MSI_ViewExecute(view
, 0);
2620 if (rc
!= ERROR_SUCCESS
)
2622 MSI_ViewClose(view
);
2623 msiobj_release(&view
->hdr
);
2631 MSIRECORD
* row
= 0;
2633 rc
= MSI_ViewFetch(view
,&row
);
2634 if (rc
!= ERROR_SUCCESS
)
2640 name
= MSI_RecordGetString(row
,1);
2642 /* This helper function now does ALL the work */
2643 TRACE("Dir %s ...\n",debugstr_w(name
));
2644 load_folder(package
,name
);
2645 path
= resolve_folder(package
,name
,FALSE
,TRUE
,NULL
);
2646 TRACE("resolves to %s\n",debugstr_w(path
));
2647 HeapFree( GetProcessHeap(), 0, path
);
2649 msiobj_release(&row
->hdr
);
2651 MSI_ViewClose(view
);
2652 msiobj_release(&view
->hdr
);
2655 TRACE("File calculations %i files\n",package
->loaded_files
);
2657 for (i
= 0; i
< package
->loaded_files
; i
++)
2659 MSICOMPONENT
* comp
= NULL
;
2660 MSIFILE
* file
= NULL
;
2662 file
= &package
->files
[i
];
2663 if (file
->ComponentIndex
>= 0)
2664 comp
= &package
->components
[file
->ComponentIndex
];
2666 if (file
->Temporary
== TRUE
)
2673 /* calculate target */
2674 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, NULL
);
2676 HeapFree(GetProcessHeap(),0,file
->TargetPath
);
2678 TRACE("file %s is named %s\n",
2679 debugstr_w(file
->File
),debugstr_w(file
->FileName
));
2681 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
2683 HeapFree(GetProcessHeap(),0,p
);
2685 TRACE("file %s resolves to %s\n",
2686 debugstr_w(file
->File
),debugstr_w(file
->TargetPath
));
2688 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
2691 comp
->Cost
+= file
->FileSize
;
2701 static const WCHAR name
[] =
2703 static const WCHAR name_fmt
[] =
2704 {'%','u','.','%','u','.','%','u','.','%','u',0};
2705 WCHAR filever
[0x100];
2706 VS_FIXEDFILEINFO
*lpVer
;
2708 TRACE("Version comparison.. \n");
2709 versize
= GetFileVersionInfoSizeW(file
->TargetPath
,&handle
);
2710 version
= HeapAlloc(GetProcessHeap(),0,versize
);
2711 GetFileVersionInfoW(file
->TargetPath
, 0, versize
, version
);
2713 VerQueryValueW(version
, name
, (LPVOID
*)&lpVer
, &sz
);
2715 sprintfW(filever
,name_fmt
,
2716 HIWORD(lpVer
->dwFileVersionMS
),
2717 LOWORD(lpVer
->dwFileVersionMS
),
2718 HIWORD(lpVer
->dwFileVersionLS
),
2719 LOWORD(lpVer
->dwFileVersionLS
));
2721 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
2722 debugstr_w(filever
));
2723 if (strcmpiW(filever
,file
->Version
)<0)
2726 FIXME("cost should be diff in size\n");
2727 comp
->Cost
+= file
->FileSize
;
2731 HeapFree(GetProcessHeap(),0,version
);
2739 TRACE("Evaluating Condition Table\n");
2741 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
2742 if (rc
== ERROR_SUCCESS
)
2744 rc
= MSI_ViewExecute(view
, 0);
2745 if (rc
!= ERROR_SUCCESS
)
2747 MSI_ViewClose(view
);
2748 msiobj_release(&view
->hdr
);
2755 MSIRECORD
* row
= 0;
2758 rc
= MSI_ViewFetch(view
,&row
);
2760 if (rc
!= ERROR_SUCCESS
)
2766 Feature
= MSI_RecordGetString(row
,1);
2768 feature_index
= get_loaded_feature(package
,Feature
);
2769 if (feature_index
< 0)
2770 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature
));
2774 Condition
= MSI_RecordGetString(row
,3);
2776 if (MSI_EvaluateConditionW(package
,Condition
) ==
2779 int level
= MSI_RecordGetInteger(row
,2);
2780 TRACE("Reseting feature %s to level %i\n",
2781 debugstr_w(Feature
), level
);
2782 package
->features
[feature_index
].Level
= level
;
2786 msiobj_release(&row
->hdr
);
2788 MSI_ViewClose(view
);
2789 msiobj_release(&view
->hdr
);
2792 TRACE("Enabling or Disabling Components\n");
2793 for (i
= 0; i
< package
->loaded_components
; i
++)
2795 if (package
->components
[i
].Condition
[0])
2797 if (MSI_EvaluateConditionW(package
,
2798 package
->components
[i
].Condition
) == MSICONDITION_FALSE
)
2800 TRACE("Disabling component %s\n",
2801 debugstr_w(package
->components
[i
].Component
));
2802 package
->components
[i
].Enabled
= FALSE
;
2807 MSI_SetPropertyW(package
,szCosting
,szOne
);
2808 /* set default run level if not set */
2809 level
= load_dynamic_property(package
,szlevel
,NULL
);
2811 MSI_SetPropertyW(package
,szlevel
, szOne
);
2813 HeapFree(GetProcessHeap(),0,level
);
2815 ACTION_UpdateInstallStates(package
);
2817 return SetFeatureStates(package
);
2821 * This is a helper function for handling embedded cabinet media
2823 static UINT
writeout_cabinet_stream(MSIPACKAGE
*package
, LPCWSTR stream_name
,
2831 WCHAR tmp
[MAX_PATH
];
2833 rc
= read_raw_stream_data(package
->db
,stream_name
,&data
,&size
);
2834 if (rc
!= ERROR_SUCCESS
)
2838 if (MSI_GetPropertyW(package
, cszTempFolder
, tmp
, &write
))
2839 GetTempPathW(MAX_PATH
,tmp
);
2841 GetTempFileNameW(tmp
,stream_name
,0,source
);
2843 track_tempfile(package
,strrchrW(source
,'\\'), source
);
2844 the_file
= CreateFileW(source
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
2845 FILE_ATTRIBUTE_NORMAL
, NULL
);
2847 if (the_file
== INVALID_HANDLE_VALUE
)
2849 ERR("Unable to create file %s\n",debugstr_w(source
));
2850 rc
= ERROR_FUNCTION_FAILED
;
2854 WriteFile(the_file
,data
,size
,&write
,NULL
);
2855 CloseHandle(the_file
);
2856 TRACE("wrote %li bytes to %s\n",write
,debugstr_w(source
));
2858 HeapFree(GetProcessHeap(),0,data
);
2863 /* Support functions for FDI functions */
2866 MSIPACKAGE
* package
;
2871 static void * cabinet_alloc(ULONG cb
)
2873 return HeapAlloc(GetProcessHeap(), 0, cb
);
2876 static void cabinet_free(void *pv
)
2878 HeapFree(GetProcessHeap(), 0, pv
);
2881 static INT_PTR
cabinet_open(char *pszFile
, int oflag
, int pmode
)
2884 DWORD dwShareMode
= 0;
2885 DWORD dwCreateDisposition
= OPEN_EXISTING
;
2886 switch (oflag
& _O_ACCMODE
)
2889 dwAccess
= GENERIC_READ
;
2890 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_DELETE
;
2893 dwAccess
= GENERIC_WRITE
;
2894 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
2897 dwAccess
= GENERIC_READ
| GENERIC_WRITE
;
2898 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
2901 if ((oflag
& (_O_CREAT
| _O_EXCL
)) == (_O_CREAT
| _O_EXCL
))
2902 dwCreateDisposition
= CREATE_NEW
;
2903 else if (oflag
& _O_CREAT
)
2904 dwCreateDisposition
= CREATE_ALWAYS
;
2905 return (INT_PTR
)CreateFileA(pszFile
, dwAccess
, dwShareMode
, NULL
,
2906 dwCreateDisposition
, 0, NULL
);
2909 static UINT
cabinet_read(INT_PTR hf
, void *pv
, UINT cb
)
2912 if (ReadFile((HANDLE
)hf
, pv
, cb
, &dwRead
, NULL
))
2917 static UINT
cabinet_write(INT_PTR hf
, void *pv
, UINT cb
)
2920 if (WriteFile((HANDLE
)hf
, pv
, cb
, &dwWritten
, NULL
))
2925 static int cabinet_close(INT_PTR hf
)
2927 return CloseHandle((HANDLE
)hf
) ? 0 : -1;
2930 static long cabinet_seek(INT_PTR hf
, long dist
, int seektype
)
2932 /* flags are compatible and so are passed straight through */
2933 return SetFilePointer((HANDLE
)hf
, dist
, NULL
, seektype
);
2936 static INT_PTR
cabinet_notify(FDINOTIFICATIONTYPE fdint
, PFDINOTIFICATION pfdin
)
2938 /* FIXME: try to do more processing in this function */
2941 case fdintCOPY_FILE
:
2943 CabData
*data
= (CabData
*) pfdin
->pv
;
2944 ULONG len
= strlen(data
->cab_path
) + strlen(pfdin
->psz1
);
2949 LPWSTR tracknametmp
;
2950 static const WCHAR tmpprefix
[] = {'C','A','B','T','M','P','_',0};
2952 if (data
->file_name
&& lstrcmpiA(data
->file_name
,pfdin
->psz1
))
2955 file
= cabinet_alloc((len
+1)*sizeof(char));
2956 strcpy(file
, data
->cab_path
);
2957 strcat(file
, pfdin
->psz1
);
2959 TRACE("file: %s\n", debugstr_a(file
));
2961 /* track this file so it can be deleted if not installed */
2962 trackpath
=strdupAtoW(file
);
2963 tracknametmp
=strdupAtoW(strrchr(file
,'\\')+1);
2964 trackname
= HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp
) +
2965 strlenW(tmpprefix
)+1) * sizeof(WCHAR
));
2967 strcpyW(trackname
,tmpprefix
);
2968 strcatW(trackname
,tracknametmp
);
2970 track_tempfile(data
->package
, trackname
, trackpath
);
2972 HeapFree(GetProcessHeap(),0,trackpath
);
2973 HeapFree(GetProcessHeap(),0,trackname
);
2974 HeapFree(GetProcessHeap(),0,tracknametmp
);
2976 return cabinet_open(file
, _O_WRONLY
| _O_CREAT
, 0);
2978 case fdintCLOSE_FILE_INFO
:
2982 if (!DosDateTimeToFileTime(pfdin
->date
, pfdin
->time
, &ft
))
2984 if (!LocalFileTimeToFileTime(&ft
, &ftLocal
))
2986 if (!SetFileTime((HANDLE
)pfdin
->hf
, &ftLocal
, 0, &ftLocal
))
2989 cabinet_close(pfdin
->hf
);
2997 /***********************************************************************
2998 * extract_cabinet_file
3000 * Extract files from a cab file.
3002 static BOOL
extract_a_cabinet_file(MSIPACKAGE
* package
, const WCHAR
* source
,
3003 const WCHAR
* path
, const WCHAR
* file
)
3013 TRACE("Extracting %s (%s) to %s\n",debugstr_w(source
),
3014 debugstr_w(file
), debugstr_w(path
));
3016 hfdi
= FDICreate(cabinet_alloc
,
3027 ERR("FDICreate failed\n");
3031 if (!(cabinet
= strdupWtoA( source
)))
3036 if (!(cab_path
= strdupWtoA( path
)))
3039 HeapFree(GetProcessHeap(), 0, cabinet
);
3043 data
.package
= package
;
3044 data
.cab_path
= cab_path
;
3046 file_name
= strdupWtoA(file
);
3049 data
.file_name
= file_name
;
3051 ret
= FDICopy(hfdi
, cabinet
, "", 0, cabinet_notify
, NULL
, &data
);
3054 ERR("FDICopy failed\n");
3058 HeapFree(GetProcessHeap(), 0, cabinet
);
3059 HeapFree(GetProcessHeap(), 0, cab_path
);
3060 HeapFree(GetProcessHeap(), 0, file_name
);
3065 static UINT
ready_media_for_file(MSIPACKAGE
*package
, WCHAR
* path
,
3068 UINT rc
= ERROR_SUCCESS
;
3069 MSIRECORD
* row
= 0;
3070 static WCHAR source
[MAX_PATH
];
3071 static const WCHAR ExecSeqQuery
[] =
3072 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3073 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3074 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
3075 ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ',
3076 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0};
3080 static UINT last_sequence
= 0;
3082 if (file
->Attributes
& msidbFileAttributesNoncompressed
)
3084 TRACE("Uncompressed File, no media to ready.\n");
3085 return ERROR_SUCCESS
;
3088 if (file
->Sequence
<= last_sequence
)
3090 TRACE("Media already ready (%u, %u)\n",file
->Sequence
,last_sequence
);
3091 /*extract_a_cabinet_file(package, source,path,file->File); */
3092 return ERROR_SUCCESS
;
3095 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, file
->Sequence
);
3097 return ERROR_FUNCTION_FAILED
;
3099 seq
= MSI_RecordGetInteger(row
,2);
3100 last_sequence
= seq
;
3102 cab
= MSI_RecordGetString(row
,4);
3105 TRACE("Source is CAB %s\n",debugstr_w(cab
));
3106 /* the stream does not contain the # character */
3109 writeout_cabinet_stream(package
,&cab
[1],source
);
3110 strcpyW(path
,source
);
3111 *(strrchrW(path
,'\\')+1)=0;
3116 if (MSI_GetPropertyW(package
, cszSourceDir
, source
, &sz
))
3118 ERR("No Source dir defined \n");
3119 rc
= ERROR_FUNCTION_FAILED
;
3123 strcpyW(path
,source
);
3124 strcatW(source
,cab
);
3125 /* extract the cab file into a folder in the temp folder */
3127 if (MSI_GetPropertyW(package
, cszTempFolder
,path
, &sz
)
3129 GetTempPathW(MAX_PATH
,path
);
3132 rc
= !extract_a_cabinet_file(package
, source
,path
,NULL
);
3137 MSI_GetPropertyW(package
,cszSourceDir
,source
,&sz
);
3138 strcpyW(path
,source
);
3140 msiobj_release(&row
->hdr
);
3144 inline static UINT
create_component_directory ( MSIPACKAGE
* package
, INT component
)
3146 UINT rc
= ERROR_SUCCESS
;
3148 LPWSTR install_path
;
3150 install_path
= resolve_folder(package
, package
->components
[component
].Directory
,
3151 FALSE
, FALSE
, &folder
);
3153 return ERROR_FUNCTION_FAILED
;
3155 /* create the path */
3156 if (folder
->State
== 0)
3158 create_full_pathW(install_path
);
3161 HeapFree(GetProcessHeap(), 0, install_path
);
3166 static UINT
ACTION_InstallFiles(MSIPACKAGE
*package
)
3168 UINT rc
= ERROR_SUCCESS
;
3171 WCHAR uipath
[MAX_PATH
];
3174 return ERROR_INVALID_HANDLE
;
3176 /* increment progress bar each time action data is sent */
3177 ui_progress(package
,1,1,0,0);
3179 for (index
= 0; index
< package
->loaded_files
; index
++)
3181 WCHAR path_to_source
[MAX_PATH
];
3184 file
= &package
->files
[index
];
3186 if (file
->Temporary
)
3190 if (!ACTION_VerifyComponentForAction(package
, file
->ComponentIndex
,
3191 INSTALLSTATE_LOCAL
))
3193 ui_progress(package
,2,file
->FileSize
,0,0);
3194 TRACE("File %s is not scheduled for install\n",
3195 debugstr_w(file
->File
));
3200 if ((file
->State
== 1) || (file
->State
== 2))
3203 MSICOMPONENT
* comp
= NULL
;
3205 TRACE("Installing %s\n",debugstr_w(file
->File
));
3206 rc
= ready_media_for_file(package
, path_to_source
, file
);
3209 * our file table could change here because a new temp file
3210 * may have been created
3212 file
= &package
->files
[index
];
3213 if (rc
!= ERROR_SUCCESS
)
3215 ERR("Unable to ready media\n");
3216 rc
= ERROR_FUNCTION_FAILED
;
3220 create_component_directory( package
, file
->ComponentIndex
);
3222 /* recalculate file paths because things may have changed */
3224 if (file
->ComponentIndex
>= 0)
3225 comp
= &package
->components
[file
->ComponentIndex
];
3227 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, NULL
);
3228 HeapFree(GetProcessHeap(),0,file
->TargetPath
);
3230 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
3231 HeapFree(GetProcessHeap(),0,p
);
3233 if (file
->Attributes
& msidbFileAttributesNoncompressed
)
3235 p
= resolve_folder(package
, comp
->Directory
, TRUE
, FALSE
, NULL
);
3236 file
->SourcePath
= build_directory_name(2, p
, file
->ShortName
);
3237 HeapFree(GetProcessHeap(),0,p
);
3240 file
->SourcePath
= build_directory_name(2, path_to_source
,
3244 TRACE("file paths %s to %s\n",debugstr_w(file
->SourcePath
),
3245 debugstr_w(file
->TargetPath
));
3248 uirow
=MSI_CreateRecord(9);
3249 MSI_RecordSetStringW(uirow
,1,file
->File
);
3250 strcpyW(uipath
,file
->TargetPath
);
3251 *(strrchrW(uipath
,'\\')+1)=0;
3252 MSI_RecordSetStringW(uirow
,9,uipath
);
3253 MSI_RecordSetInteger(uirow
,6,file
->FileSize
);
3254 ui_actiondata(package
,szInstallFiles
,uirow
);
3255 msiobj_release( &uirow
->hdr
);
3256 ui_progress(package
,2,file
->FileSize
,0,0);
3259 if (file
->Attributes
& msidbFileAttributesNoncompressed
)
3260 rc
= CopyFileW(file
->SourcePath
,file
->TargetPath
,FALSE
);
3262 rc
= MoveFileW(file
->SourcePath
, file
->TargetPath
);
3266 rc
= GetLastError();
3267 ERR("Unable to move/copy file (%s -> %s) (error %d)\n",
3268 debugstr_w(file
->SourcePath
), debugstr_w(file
->TargetPath
),
3270 if (rc
== ERROR_ALREADY_EXISTS
&& file
->State
== 2)
3272 if (!CopyFileW(file
->SourcePath
,file
->TargetPath
,FALSE
))
3273 ERR("Unable to copy file (%s -> %s) (error %ld)\n",
3274 debugstr_w(file
->SourcePath
),
3275 debugstr_w(file
->TargetPath
), GetLastError());
3276 if (!(file
->Attributes
& msidbFileAttributesNoncompressed
))
3277 DeleteFileW(file
->SourcePath
);
3280 else if (rc
== ERROR_FILE_NOT_FOUND
)
3282 ERR("Source File Not Found! Continuing\n");
3285 else if (file
->Attributes
& msidbFileAttributesVital
)
3287 ERR("Ignoring Error and continuing (nonvital file)...\n");
3302 inline static UINT
get_file_target(MSIPACKAGE
*package
, LPCWSTR file_key
,
3303 LPWSTR
* file_source
)
3308 return ERROR_INVALID_HANDLE
;
3310 for (index
= 0; index
< package
->loaded_files
; index
++)
3312 if (strcmpW(file_key
,package
->files
[index
].File
)==0)
3314 if (package
->files
[index
].State
>= 2)
3316 *file_source
= strdupW(package
->files
[index
].TargetPath
);
3317 return ERROR_SUCCESS
;
3320 return ERROR_FILE_NOT_FOUND
;
3324 return ERROR_FUNCTION_FAILED
;
3327 static UINT
ACTION_DuplicateFiles(MSIPACKAGE
*package
)
3331 MSIRECORD
* row
= 0;
3332 static const WCHAR ExecSeqQuery
[] =
3333 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3334 '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0};
3337 return ERROR_INVALID_HANDLE
;
3339 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3340 if (rc
!= ERROR_SUCCESS
)
3341 return ERROR_SUCCESS
;
3343 rc
= MSI_ViewExecute(view
, 0);
3344 if (rc
!= ERROR_SUCCESS
)
3346 MSI_ViewClose(view
);
3347 msiobj_release(&view
->hdr
);
3353 WCHAR
*file_source
= NULL
;
3354 WCHAR dest_name
[0x100];
3355 LPWSTR dest_path
, dest
;
3356 LPCWSTR file_key
, component
;
3357 INT component_index
;
3361 rc
= MSI_ViewFetch(view
,&row
);
3362 if (rc
!= ERROR_SUCCESS
)
3368 component
= MSI_RecordGetString(row
,2);
3371 ERR("Unable to get component\n");
3372 msiobj_release(&row
->hdr
);
3376 component_index
= get_loaded_component(package
,component
);
3378 if (!ACTION_VerifyComponentForAction(package
, component_index
,
3379 INSTALLSTATE_LOCAL
))
3381 TRACE("Skipping copy due to disabled component\n");
3383 /* the action taken was the same as the current install state */
3384 package
->components
[component_index
].Action
=
3385 package
->components
[component_index
].Installed
;
3387 msiobj_release(&row
->hdr
);
3391 package
->components
[component_index
].Action
= INSTALLSTATE_LOCAL
;
3393 file_key
= MSI_RecordGetString(row
,3);
3396 ERR("Unable to get file key\n");
3397 msiobj_release(&row
->hdr
);
3401 rc
= get_file_target(package
,file_key
,&file_source
);
3403 if (rc
!= ERROR_SUCCESS
)
3405 ERR("Original file unknown %s\n",debugstr_w(file_key
));
3406 msiobj_release(&row
->hdr
);
3407 HeapFree(GetProcessHeap(),0,file_source
);
3411 if (MSI_RecordIsNull(row
,4))
3413 strcpyW(dest_name
,strrchrW(file_source
,'\\')+1);
3418 MSI_RecordGetStringW(row
,4,dest_name
,&sz
);
3419 reduce_to_longfilename(dest_name
);
3422 if (MSI_RecordIsNull(row
,5))
3425 dest_path
= strdupW(file_source
);
3426 p
= strrchrW(dest_path
,'\\');
3433 destkey
= MSI_RecordGetString(row
,5);
3434 dest_path
= resolve_folder(package
, destkey
, FALSE
,FALSE
,NULL
);
3437 ERR("Unable to get destination folder\n");
3438 msiobj_release(&row
->hdr
);
3439 HeapFree(GetProcessHeap(),0,file_source
);
3444 dest
= build_directory_name(2, dest_path
, dest_name
);
3446 TRACE("Duplicating file %s to %s\n",debugstr_w(file_source
),
3449 if (strcmpW(file_source
,dest
))
3450 rc
= !CopyFileW(file_source
,dest
,TRUE
);
3454 if (rc
!= ERROR_SUCCESS
)
3455 ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source
), debugstr_w(dest_path
), GetLastError());
3457 FIXME("We should track these duplicate files as well\n");
3459 msiobj_release(&row
->hdr
);
3460 HeapFree(GetProcessHeap(),0,dest_path
);
3461 HeapFree(GetProcessHeap(),0,dest
);
3462 HeapFree(GetProcessHeap(),0,file_source
);
3464 MSI_ViewClose(view
);
3465 msiobj_release(&view
->hdr
);
3470 /* OK this value is "interpreted" and then formatted based on the
3471 first few characters */
3472 static LPSTR
parse_value(MSIPACKAGE
*package
, WCHAR
*value
, DWORD
*type
,
3476 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
3482 LPWSTR deformated
= NULL
;
3485 deformat_string(package
, &value
[2], &deformated
);
3487 /* binary value type */
3491 *size
= (strlenW(ptr
)/2)+1;
3493 *size
= strlenW(ptr
)/2;
3495 data
= HeapAlloc(GetProcessHeap(),0,*size
);
3501 /* if uneven pad with a zero in front */
3507 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
3509 TRACE("Uneven byte count\n");
3517 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
3520 HeapFree(GetProcessHeap(),0,deformated
);
3522 TRACE("Data %li bytes(%i)\n",*size
,count
);
3529 deformat_string(package
, &value
[1], &deformated
);
3532 *size
= sizeof(DWORD
);
3533 data
= HeapAlloc(GetProcessHeap(),0,*size
);
3539 if ( (*p
< '0') || (*p
> '9') )
3545 if (deformated
[0] == '-')
3548 TRACE("DWORD %li\n",*(LPDWORD
)data
);
3550 HeapFree(GetProcessHeap(),0,deformated
);
3555 static const WCHAR szMulti
[] = {'[','~',']',0};
3564 *type
=REG_EXPAND_SZ
;
3572 if (strstrW(value
,szMulti
))
3573 *type
= REG_MULTI_SZ
;
3575 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
3580 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
3584 MSIRECORD
* row
= 0;
3585 static const WCHAR ExecSeqQuery
[] =
3586 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3587 '`','R','e','g','i','s','t','r','y','`',0 };
3590 return ERROR_INVALID_HANDLE
;
3592 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3593 if (rc
!= ERROR_SUCCESS
)
3594 return ERROR_SUCCESS
;
3596 rc
= MSI_ViewExecute(view
, 0);
3597 if (rc
!= ERROR_SUCCESS
)
3599 MSI_ViewClose(view
);
3600 msiobj_release(&view
->hdr
);
3604 /* increment progress bar each time action data is sent */
3605 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
3609 static const WCHAR szHCR
[] =
3610 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
3611 'R','O','O','T','\\',0};
3612 static const WCHAR szHCU
[] =
3613 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
3614 'U','S','E','R','\\',0};
3615 static const WCHAR szHLM
[] =
3616 {'H','K','E','Y','_','L','O','C','A','L','_',
3617 'M','A','C','H','I','N','E','\\',0};
3618 static const WCHAR szHU
[] =
3619 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
3621 LPSTR value_data
= NULL
;
3622 HKEY root_key
, hkey
;
3624 LPWSTR value
, key
, name
, component
, deformated
;
3626 INT component_index
;
3630 BOOL check_first
= FALSE
;
3632 rc
= MSI_ViewFetch(view
,&row
);
3633 if (rc
!= ERROR_SUCCESS
)
3638 ui_progress(package
,2,0,0,0);
3645 component
= load_dynamic_stringW(row
, 6);
3646 component_index
= get_loaded_component(package
,component
);
3648 if (!ACTION_VerifyComponentForAction(package
, component_index
,
3649 INSTALLSTATE_LOCAL
))
3651 TRACE("Skipping write due to disabled component\n");
3652 msiobj_release(&row
->hdr
);
3654 package
->components
[component_index
].Action
=
3655 package
->components
[component_index
].Installed
;
3660 package
->components
[component_index
].Action
= INSTALLSTATE_LOCAL
;
3662 name
= load_dynamic_stringW(row
, 4);
3663 if( MSI_RecordIsNull(row
,5) && name
)
3665 /* null values can have special meanings */
3666 if (name
[0]=='-' && name
[1] == 0)
3668 msiobj_release(&row
->hdr
);
3671 else if ((name
[0]=='+' && name
[1] == 0) ||
3672 (name
[0] == '*' && name
[1] == 0))
3674 HeapFree(GetProcessHeap(),0,name
);
3680 root
= MSI_RecordGetInteger(row
,2);
3681 key
= load_dynamic_stringW(row
, 3);
3684 /* get the root key */
3687 case 0: root_key
= HKEY_CLASSES_ROOT
;
3690 case 1: root_key
= HKEY_CURRENT_USER
;
3693 case 2: root_key
= HKEY_LOCAL_MACHINE
;
3696 case 3: root_key
= HKEY_USERS
;
3700 ERR("Unknown root %i\n",root
);
3707 msiobj_release(&row
->hdr
);
3711 deformat_string(package
, key
, &deformated
);
3712 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
3713 uikey
= HeapAlloc(GetProcessHeap(), 0, size
*sizeof(WCHAR
));
3714 strcpyW(uikey
,szRoot
);
3715 strcatW(uikey
,deformated
);
3717 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
3719 ERR("Could not create key %s\n",debugstr_w(deformated
));
3720 msiobj_release(&row
->hdr
);
3721 HeapFree(GetProcessHeap(),0,deformated
);
3724 HeapFree(GetProcessHeap(),0,deformated
);
3726 value
= load_dynamic_stringW(row
,5);
3728 value_data
= parse_value(package
, value
, &type
, &size
);
3731 static const WCHAR szEmpty
[] = {0};
3732 value_data
= (LPSTR
)strdupW(szEmpty
);
3737 deformat_string(package
, name
, &deformated
);
3739 /* get the double nulls to terminate SZ_MULTI */
3740 if (type
== REG_MULTI_SZ
)
3741 size
+=sizeof(WCHAR
);
3745 TRACE("Setting value %s of %s\n",debugstr_w(deformated
),
3747 RegSetValueExW(hkey
, deformated
, 0, type
, value_data
, size
);
3752 rc
= RegQueryValueExW(hkey
, deformated
, NULL
, NULL
, NULL
, &sz
);
3753 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
3755 TRACE("value %s of %s checked already exists\n",
3756 debugstr_w(deformated
), debugstr_w(uikey
));
3760 TRACE("Checked and setting value %s of %s\n",
3761 debugstr_w(deformated
), debugstr_w(uikey
));
3762 RegSetValueExW(hkey
, deformated
, 0, type
, value_data
, size
);
3766 uirow
= MSI_CreateRecord(3);
3767 MSI_RecordSetStringW(uirow
,2,deformated
);
3768 MSI_RecordSetStringW(uirow
,1,uikey
);
3771 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
3773 MSI_RecordSetStringW(uirow
,3,value
);
3775 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
3776 msiobj_release( &uirow
->hdr
);
3778 HeapFree(GetProcessHeap(),0,value_data
);
3779 HeapFree(GetProcessHeap(),0,value
);
3780 HeapFree(GetProcessHeap(),0,deformated
);
3782 msiobj_release(&row
->hdr
);
3785 HeapFree(GetProcessHeap(),0,uikey
);
3786 HeapFree(GetProcessHeap(),0,key
);
3787 HeapFree(GetProcessHeap(),0,name
);
3788 HeapFree(GetProcessHeap(),0,component
);
3790 MSI_ViewClose(view
);
3791 msiobj_release(&view
->hdr
);
3795 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
3797 package
->script
->CurrentlyScripting
= TRUE
;
3799 return ERROR_SUCCESS
;
3803 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
3807 static const WCHAR q1
[]=
3808 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3809 '`','R','e','g','i','s','t','r','y','`',0};
3812 MSIRECORD
* row
= 0;
3815 TRACE(" InstallValidate \n");
3817 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
3818 if (rc
!= ERROR_SUCCESS
)
3819 return ERROR_SUCCESS
;
3821 rc
= MSI_ViewExecute(view
, 0);
3822 if (rc
!= ERROR_SUCCESS
)
3824 MSI_ViewClose(view
);
3825 msiobj_release(&view
->hdr
);
3830 rc
= MSI_ViewFetch(view
,&row
);
3831 if (rc
!= ERROR_SUCCESS
)
3838 msiobj_release(&row
->hdr
);
3840 MSI_ViewClose(view
);
3841 msiobj_release(&view
->hdr
);
3843 total
= total
+ progress
* REG_PROGRESS_VALUE
;
3844 total
= total
+ package
->loaded_components
* COMPONENT_PROGRESS_VALUE
;
3845 for (i
=0; i
< package
->loaded_files
; i
++)
3846 total
+= package
->files
[i
].FileSize
;
3847 ui_progress(package
,0,total
,0,0);
3849 for(i
= 0; i
< package
->loaded_features
; i
++)
3851 MSIFEATURE
* feature
= &package
->features
[i
];
3852 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
3853 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
3854 feature
->ActionRequest
);
3857 return ERROR_SUCCESS
;
3860 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
3863 MSIQUERY
* view
= NULL
;
3864 MSIRECORD
* row
= 0;
3865 static const WCHAR ExecSeqQuery
[] =
3866 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3867 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3868 static const WCHAR title
[]=
3869 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3871 TRACE("Checking launch conditions\n");
3873 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3874 if (rc
!= ERROR_SUCCESS
)
3875 return ERROR_SUCCESS
;
3877 rc
= MSI_ViewExecute(view
, 0);
3878 if (rc
!= ERROR_SUCCESS
)
3880 MSI_ViewClose(view
);
3881 msiobj_release(&view
->hdr
);
3886 while (rc
== ERROR_SUCCESS
)
3889 LPWSTR message
= NULL
;
3891 rc
= MSI_ViewFetch(view
,&row
);
3892 if (rc
!= ERROR_SUCCESS
)
3898 cond
= load_dynamic_stringW(row
,1);
3900 if (MSI_EvaluateConditionW(package
,cond
) != MSICONDITION_TRUE
)
3903 message
= load_dynamic_stringW(row
,2);
3904 deformat_string(package
,message
,&deformated
);
3905 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
3906 HeapFree(GetProcessHeap(),0,message
);
3907 HeapFree(GetProcessHeap(),0,deformated
);
3908 rc
= ERROR_FUNCTION_FAILED
;
3910 HeapFree(GetProcessHeap(),0,cond
);
3911 msiobj_release(&row
->hdr
);
3913 MSI_ViewClose(view
);
3914 msiobj_release(&view
->hdr
);
3918 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, INT
3921 MSICOMPONENT
* cmp
= &package
->components
[component_index
];
3923 if (cmp
->KeyPath
[0]==0)
3925 LPWSTR p
= resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,NULL
);
3928 if (cmp
->Attributes
& msidbComponentAttributesRegistryKeyPath
)
3930 MSIRECORD
* row
= 0;
3932 LPWSTR key
,deformated
,buffer
,name
,deformated_name
;
3933 static const WCHAR ExecSeqQuery
[] =
3934 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3935 '`','R','e','g','i','s','t','r','y','`',' ',
3936 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3937 ' ','=',' ' ,'\'','%','s','\'',0 };
3938 static const WCHAR fmt
[]={'%','0','2','i',':','\\','%','s','\\',0};
3939 static const WCHAR fmt2
[]=
3940 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3942 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
,cmp
->KeyPath
);
3946 root
= MSI_RecordGetInteger(row
,2);
3947 key
= load_dynamic_stringW(row
, 3);
3948 name
= load_dynamic_stringW(row
, 4);
3949 deformat_string(package
, key
, &deformated
);
3950 deformat_string(package
, name
, &deformated_name
);
3952 len
= strlenW(deformated
) + 6;
3953 if (deformated_name
)
3954 len
+=strlenW(deformated_name
);
3956 buffer
= HeapAlloc(GetProcessHeap(),0, len
*sizeof(WCHAR
));
3958 if (deformated_name
)
3959 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
3961 sprintfW(buffer
,fmt
,root
,deformated
);
3963 HeapFree(GetProcessHeap(),0,key
);
3964 HeapFree(GetProcessHeap(),0,deformated
);
3965 HeapFree(GetProcessHeap(),0,name
);
3966 HeapFree(GetProcessHeap(),0,deformated_name
);
3967 msiobj_release(&row
->hdr
);
3971 else if (cmp
->Attributes
& msidbComponentAttributesODBCDataSource
)
3973 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3979 j
= get_loaded_file(package
,cmp
->KeyPath
);
3983 LPWSTR p
= strdupW(package
->files
[j
].TargetPath
);
3990 static HKEY
openSharedDLLsKey()
3993 static const WCHAR path
[] =
3994 {'S','o','f','t','w','a','r','e','\\',
3995 'M','i','c','r','o','s','o','f','t','\\',
3996 'W','i','n','d','o','w','s','\\',
3997 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3998 'S','h','a','r','e','d','D','L','L','s',0};
4000 RegCreateKeyW(HKEY_LOCAL_MACHINE
,path
,&hkey
);
4004 static UINT
ACTION_GetSharedDLLsCount(LPCWSTR dll
)
4009 DWORD sz
= sizeof(count
);
4012 hkey
= openSharedDLLsKey();
4013 rc
= RegQueryValueExW(hkey
, dll
, NULL
, &type
, (LPBYTE
)&count
, &sz
);
4014 if (rc
!= ERROR_SUCCESS
)
4020 static UINT
ACTION_WriteSharedDLLsCount(LPCWSTR path
, UINT count
)
4024 hkey
= openSharedDLLsKey();
4026 RegSetValueExW(hkey
,path
,0,REG_DWORD
,
4027 (LPBYTE
)&count
,sizeof(count
));
4029 RegDeleteValueW(hkey
,path
);
4035 * Return TRUE if the count should be written out and FALSE if not
4037 static void ACTION_RefCountComponent( MSIPACKAGE
* package
, UINT index
)
4043 /* only refcount DLLs */
4044 if (package
->components
[index
].KeyPath
[0]==0 ||
4045 package
->components
[index
].Attributes
&
4046 msidbComponentAttributesRegistryKeyPath
||
4047 package
->components
[index
].Attributes
&
4048 msidbComponentAttributesODBCDataSource
)
4052 count
= ACTION_GetSharedDLLsCount(package
->components
[index
].
4054 write
= (count
> 0);
4056 if (package
->components
[index
].Attributes
&
4057 msidbComponentAttributesSharedDllRefCount
)
4061 /* increment counts */
4062 for (j
= 0; j
< package
->loaded_features
; j
++)
4066 if (!ACTION_VerifyFeatureForAction(package
,j
,INSTALLSTATE_LOCAL
))
4069 for (i
= 0; i
< package
->features
[j
].ComponentCount
; i
++)
4071 if (package
->features
[j
].Components
[i
] == index
)
4075 /* decrement counts */
4076 for (j
= 0; j
< package
->loaded_features
; j
++)
4079 if (!ACTION_VerifyFeatureForAction(package
,j
,INSTALLSTATE_ABSENT
))
4082 for (i
= 0; i
< package
->features
[j
].ComponentCount
; i
++)
4084 if (package
->features
[j
].Components
[i
] == index
)
4089 /* ref count all the files in the component */
4091 for (j
= 0; j
< package
->loaded_files
; j
++)
4093 if (package
->files
[j
].Temporary
)
4095 if (package
->files
[j
].ComponentIndex
== index
)
4096 ACTION_WriteSharedDLLsCount(package
->files
[j
].TargetPath
,count
);
4099 /* add a count for permenent */
4100 if (package
->components
[index
].Attributes
&
4101 msidbComponentAttributesPermanent
)
4104 package
->components
[index
].RefCount
= count
;
4107 ACTION_WriteSharedDLLsCount(package
->components
[index
].FullKeypath
,
4108 package
->components
[index
].RefCount
);
4112 * Ok further analysis makes me think that this work is
4113 * actually done in the PublishComponents and PublishFeatures
4114 * step, and not here. It appears like the keypath and all that is
4115 * resolved in this step, however actually written in the Publish steps.
4116 * But we will leave it here for now because it is unclear
4118 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
4121 WCHAR squished_pc
[GUID_SIZE
];
4122 WCHAR squished_cc
[GUID_SIZE
];
4125 HKEY hkey
=0,hkey2
=0;
4128 return ERROR_INVALID_HANDLE
;
4130 /* writes the Component and Features values to the registry */
4131 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
4135 rc
= MSIREG_OpenComponents(&hkey
);
4136 if (rc
!= ERROR_SUCCESS
)
4139 squash_guid(productcode
,squished_pc
);
4140 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
4141 for (i
= 0; i
< package
->loaded_components
; i
++)
4143 ui_progress(package
,2,0,0,0);
4144 if (package
->components
[i
].ComponentId
[0]!=0)
4146 WCHAR
*keypath
= NULL
;
4149 squash_guid(package
->components
[i
].ComponentId
,squished_cc
);
4151 keypath
= resolve_keypath(package
,i
);
4152 package
->components
[i
].FullKeypath
= keypath
;
4154 /* do the refcounting */
4155 ACTION_RefCountComponent( package
, i
);
4157 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
4158 debugstr_w(package
->components
[i
].Component
),
4159 debugstr_w(squished_cc
),
4160 debugstr_w(package
->components
[i
].FullKeypath
),
4161 package
->components
[i
].RefCount
);
4163 * Write the keypath out if the component is to be registered
4164 * and delete the key if the component is to be deregistered
4166 if (ACTION_VerifyComponentForAction(package
, i
,
4167 INSTALLSTATE_LOCAL
))
4169 rc
= RegCreateKeyW(hkey
,squished_cc
,&hkey2
);
4170 if (rc
!= ERROR_SUCCESS
)
4175 RegSetValueExW(hkey2
,squished_pc
,0,REG_SZ
,(LPVOID
)keypath
,
4176 (strlenW(keypath
)+1)*sizeof(WCHAR
));
4178 if (package
->components
[i
].Attributes
&
4179 msidbComponentAttributesPermanent
)
4181 static const WCHAR szPermKey
[] =
4182 { '0','0','0','0','0','0','0','0','0','0','0','0',
4183 '0','0','0','0','0','0','0', '0','0','0','0','0',
4184 '0','0','0','0','0','0','0','0',0};
4186 RegSetValueExW(hkey2
,szPermKey
,0,REG_SZ
,
4188 (strlenW(keypath
)+1)*sizeof(WCHAR
));
4194 uirow
= MSI_CreateRecord(3);
4195 MSI_RecordSetStringW(uirow
,1,productcode
);
4196 MSI_RecordSetStringW(uirow
,2,package
->components
[i
].
4198 MSI_RecordSetStringW(uirow
,3,keypath
);
4199 ui_actiondata(package
,szProcessComponents
,uirow
);
4200 msiobj_release( &uirow
->hdr
);
4203 else if (ACTION_VerifyComponentForAction(package
, i
,
4204 INSTALLSTATE_ABSENT
))
4208 rc
= RegOpenKeyW(hkey
,squished_cc
,&hkey2
);
4209 if (rc
!= ERROR_SUCCESS
)
4212 RegDeleteValueW(hkey2
,squished_pc
);
4214 /* if the key is empty delete it */
4215 res
= RegEnumKeyExW(hkey2
,0,NULL
,0,0,NULL
,0,NULL
);
4217 if (res
== ERROR_NO_MORE_ITEMS
)
4218 RegDeleteKeyW(hkey
,squished_cc
);
4221 uirow
= MSI_CreateRecord(2);
4222 MSI_RecordSetStringW(uirow
,1,productcode
);
4223 MSI_RecordSetStringW(uirow
,2,package
->components
[i
].
4225 ui_actiondata(package
,szProcessComponents
,uirow
);
4226 msiobj_release( &uirow
->hdr
);
4231 HeapFree(GetProcessHeap(), 0, productcode
);
4244 static BOOL CALLBACK
Typelib_EnumResNameProc( HMODULE hModule
, LPCWSTR lpszType
,
4245 LPWSTR lpszName
, LONG_PTR lParam
)
4248 typelib_struct
*tl_struct
= (typelib_struct
*) lParam
;
4249 static const WCHAR fmt
[] = {'%','s','\\','%','i',0};
4253 if (!IS_INTRESOURCE(lpszName
))
4255 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName
));
4259 sz
= strlenW(tl_struct
->source
)+4;
4260 sz
*= sizeof(WCHAR
);
4262 if ((INT
)lpszName
== 1)
4263 tl_struct
->path
= strdupW(tl_struct
->source
);
4266 tl_struct
->path
= HeapAlloc(GetProcessHeap(),0,sz
);
4267 sprintfW(tl_struct
->path
,fmt
,tl_struct
->source
, lpszName
);
4270 TRACE("trying %s\n", debugstr_w(tl_struct
->path
));
4271 res
= LoadTypeLib(tl_struct
->path
,&tl_struct
->ptLib
);
4272 if (!SUCCEEDED(res
))
4274 HeapFree(GetProcessHeap(),0,tl_struct
->path
);
4275 tl_struct
->path
= NULL
;
4280 ITypeLib_GetLibAttr(tl_struct
->ptLib
, &attr
);
4281 if (IsEqualGUID(&(tl_struct
->clsid
),&(attr
->guid
)))
4283 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
4287 HeapFree(GetProcessHeap(),0,tl_struct
->path
);
4288 tl_struct
->path
= NULL
;
4290 ITypeLib_ReleaseTLibAttr(tl_struct
->ptLib
, attr
);
4291 ITypeLib_Release(tl_struct
->ptLib
);
4296 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
4299 * OK this is a bit confusing.. I am given a _Component key and I believe
4300 * that the file that is being registered as a type library is the "key file
4301 * of that component" which I interpret to mean "The file in the KeyPath of
4306 MSIRECORD
* row
= 0;
4307 static const WCHAR Query
[] =
4308 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4309 '`','T','y','p','e','L','i','b','`',0};
4312 return ERROR_INVALID_HANDLE
;
4314 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
4315 if (rc
!= ERROR_SUCCESS
)
4316 return ERROR_SUCCESS
;
4318 rc
= MSI_ViewExecute(view
, 0);
4319 if (rc
!= ERROR_SUCCESS
)
4321 MSI_ViewClose(view
);
4322 msiobj_release(&view
->hdr
);
4328 WCHAR component
[0x100];
4332 typelib_struct tl_struct
;
4334 static const WCHAR szTYPELIB
[] = {'T','Y','P','E','L','I','B',0};
4336 rc
= MSI_ViewFetch(view
,&row
);
4337 if (rc
!= ERROR_SUCCESS
)
4344 MSI_RecordGetStringW(row
,3,component
,&sz
);
4346 index
= get_loaded_component(package
,component
);
4349 msiobj_release(&row
->hdr
);
4353 if (!ACTION_VerifyComponentForAction(package
, index
,
4354 INSTALLSTATE_LOCAL
))
4356 TRACE("Skipping typelib reg due to disabled component\n");
4357 msiobj_release(&row
->hdr
);
4359 package
->components
[index
].Action
=
4360 package
->components
[index
].Installed
;
4365 package
->components
[index
].Action
= INSTALLSTATE_LOCAL
;
4367 index
= get_loaded_file(package
,package
->components
[index
].KeyPath
);
4371 msiobj_release(&row
->hdr
);
4375 guid
= load_dynamic_stringW(row
,1);
4376 module
= LoadLibraryExW(package
->files
[index
].TargetPath
, NULL
,
4377 LOAD_LIBRARY_AS_DATAFILE
);
4380 CLSIDFromString(guid
, &tl_struct
.clsid
);
4381 tl_struct
.source
= strdupW(package
->files
[index
].TargetPath
);
4382 tl_struct
.path
= NULL
;
4384 EnumResourceNamesW(module
, szTYPELIB
, Typelib_EnumResNameProc
,
4385 (LONG_PTR
)&tl_struct
);
4387 if (tl_struct
.path
!= NULL
)
4390 WCHAR helpid
[0x100];
4394 MSI_RecordGetStringW(row
,6,helpid
,&sz
);
4396 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,NULL
);
4397 res
= RegisterTypeLib(tl_struct
.ptLib
,tl_struct
.path
,help
);
4398 HeapFree(GetProcessHeap(),0,help
);
4400 if (!SUCCEEDED(res
))
4401 ERR("Failed to register type library %s\n",
4402 debugstr_w(tl_struct
.path
));
4405 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
4407 TRACE("Registered %s\n", debugstr_w(tl_struct
.path
));
4410 ITypeLib_Release(tl_struct
.ptLib
);
4411 HeapFree(GetProcessHeap(),0,tl_struct
.path
);
4414 ERR("Failed to load type library %s\n",
4415 debugstr_w(tl_struct
.source
));
4417 FreeLibrary(module
);
4418 HeapFree(GetProcessHeap(),0,tl_struct
.source
);
4421 ERR("Could not load file! %s\n",
4422 debugstr_w(package
->files
[index
].TargetPath
));
4423 msiobj_release(&row
->hdr
);
4425 MSI_ViewClose(view
);
4426 msiobj_release(&view
->hdr
);
4430 static INT
load_appid(MSIPACKAGE
* package
, MSIRECORD
*row
)
4432 DWORD index
= package
->loaded_appids
;
4436 /* fill in the data */
4438 package
->loaded_appids
++;
4439 if (package
->loaded_appids
== 1)
4440 package
->appids
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIAPPID
));
4442 package
->appids
= HeapReAlloc(GetProcessHeap(),0,
4443 package
->appids
, package
->loaded_appids
* sizeof(MSIAPPID
));
4445 memset(&package
->appids
[index
],0,sizeof(MSIAPPID
));
4447 sz
= IDENTIFIER_SIZE
;
4448 MSI_RecordGetStringW(row
, 1, package
->appids
[index
].AppID
, &sz
);
4449 TRACE("loading appid %s\n",debugstr_w(package
->appids
[index
].AppID
));
4451 buffer
= load_dynamic_stringW(row
,2);
4452 deformat_string(package
,buffer
,&package
->appids
[index
].RemoteServerName
);
4453 HeapFree(GetProcessHeap(),0,buffer
);
4455 package
->appids
[index
].LocalServer
= load_dynamic_stringW(row
,3);
4456 package
->appids
[index
].ServiceParameters
= load_dynamic_stringW(row
,4);
4457 package
->appids
[index
].DllSurrogate
= load_dynamic_stringW(row
,5);
4459 package
->appids
[index
].ActivateAtStorage
= !MSI_RecordIsNull(row
,6);
4460 package
->appids
[index
].RunAsInteractiveUser
= !MSI_RecordIsNull(row
,7);
4465 static INT
load_given_appid(MSIPACKAGE
*package
, LPCWSTR appid
)
4470 static const WCHAR ExecSeqQuery
[] =
4471 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4472 '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ',
4473 '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0};
4478 /* check for appids already loaded */
4479 for (i
= 0; i
< package
->loaded_appids
; i
++)
4480 if (strcmpiW(package
->appids
[i
].AppID
,appid
)==0)
4482 TRACE("found appid %s at index %i\n",debugstr_w(appid
),i
);
4486 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, appid
);
4490 rc
= load_appid(package
, row
);
4491 msiobj_release(&row
->hdr
);
4496 static INT
load_given_progid(MSIPACKAGE
*package
, LPCWSTR progid
);
4497 static INT
load_given_class(MSIPACKAGE
*package
, LPCWSTR classid
);
4499 static INT
load_progid(MSIPACKAGE
* package
, MSIRECORD
*row
)
4501 DWORD index
= package
->loaded_progids
;
4504 /* fill in the data */
4506 package
->loaded_progids
++;
4507 if (package
->loaded_progids
== 1)
4508 package
->progids
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIPROGID
));
4510 package
->progids
= HeapReAlloc(GetProcessHeap(),0,
4511 package
->progids
, package
->loaded_progids
* sizeof(MSIPROGID
));
4513 memset(&package
->progids
[index
],0,sizeof(MSIPROGID
));
4515 package
->progids
[index
].ProgID
= load_dynamic_stringW(row
,1);
4516 TRACE("loading progid %s\n",debugstr_w(package
->progids
[index
].ProgID
));
4518 buffer
= load_dynamic_stringW(row
,2);
4519 package
->progids
[index
].ParentIndex
= load_given_progid(package
,buffer
);
4520 if (package
->progids
[index
].ParentIndex
< 0 && buffer
)
4521 FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer
));
4522 HeapFree(GetProcessHeap(),0,buffer
);
4524 buffer
= load_dynamic_stringW(row
,3);
4525 package
->progids
[index
].ClassIndex
= load_given_class(package
,buffer
);
4526 if (package
->progids
[index
].ClassIndex
< 0 && buffer
)
4527 FIXME("Unknown class %s\n",debugstr_w(buffer
));
4528 HeapFree(GetProcessHeap(),0,buffer
);
4530 package
->progids
[index
].Description
= load_dynamic_stringW(row
,4);
4532 if (!MSI_RecordIsNull(row
,6))
4534 INT icon_index
= MSI_RecordGetInteger(row
,6);
4535 LPWSTR FileName
= load_dynamic_stringW(row
,5);
4537 static const WCHAR fmt
[] = {'%','s',',','%','i',0};
4539 build_icon_path(package
,FileName
,&FilePath
);
4541 package
->progids
[index
].IconPath
=
4542 HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath
)+10)*
4545 sprintfW(package
->progids
[index
].IconPath
,fmt
,FilePath
,icon_index
);
4547 HeapFree(GetProcessHeap(),0,FilePath
);
4548 HeapFree(GetProcessHeap(),0,FileName
);
4552 buffer
= load_dynamic_stringW(row
,5);
4554 build_icon_path(package
,buffer
,&(package
->progids
[index
].IconPath
));
4555 HeapFree(GetProcessHeap(),0,buffer
);
4558 package
->progids
[index
].CurVerIndex
= -1;
4559 package
->progids
[index
].VersionIndIndex
= -1;
4561 /* if we have a parent then we may be that parents CurVer */
4562 if (package
->progids
[index
].ParentIndex
>= 0 &&
4563 package
->progids
[index
].ParentIndex
!= index
)
4565 int pindex
= package
->progids
[index
].ParentIndex
;
4566 while (package
->progids
[pindex
].ParentIndex
>= 0)
4567 pindex
= package
->progids
[pindex
].ParentIndex
;
4569 FIXME("BAD BAD need to determing if we are really the CurVer\n");
4571 package
->progids
[index
].CurVerIndex
= pindex
;
4572 package
->progids
[pindex
].VersionIndIndex
= index
;
4578 static INT
load_given_progid(MSIPACKAGE
*package
, LPCWSTR progid
)
4583 static const WCHAR ExecSeqQuery
[] =
4584 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4585 '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ',
4586 '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0};
4591 /* check for progids already loaded */
4592 for (i
= 0; i
< package
->loaded_progids
; i
++)
4593 if (strcmpiW(package
->progids
[i
].ProgID
,progid
)==0)
4595 TRACE("found progid %s at index %i\n",debugstr_w(progid
), i
);
4599 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, progid
);
4603 rc
= load_progid(package
, row
);
4604 msiobj_release(&row
->hdr
);
4609 static INT
load_class(MSIPACKAGE
* package
, MSIRECORD
*row
)
4611 DWORD index
= package
->loaded_classes
;
4615 /* fill in the data */
4617 package
->loaded_classes
++;
4618 if (package
->loaded_classes
== 1)
4619 package
->classes
= HeapAlloc(GetProcessHeap(),0,sizeof(MSICLASS
));
4621 package
->classes
= HeapReAlloc(GetProcessHeap(),0,
4622 package
->classes
, package
->loaded_classes
* sizeof(MSICLASS
));
4624 memset(&package
->classes
[index
],0,sizeof(MSICLASS
));
4626 sz
= IDENTIFIER_SIZE
;
4627 MSI_RecordGetStringW(row
, 1, package
->classes
[index
].CLSID
, &sz
);
4628 TRACE("loading class %s\n",debugstr_w(package
->classes
[index
].CLSID
));
4629 sz
= IDENTIFIER_SIZE
;
4630 MSI_RecordGetStringW(row
, 2, package
->classes
[index
].Context
, &sz
);
4631 buffer
= load_dynamic_stringW(row
,3);
4632 package
->classes
[index
].ComponentIndex
= get_loaded_component(package
,
4634 HeapFree(GetProcessHeap(),0,buffer
);
4636 package
->classes
[index
].ProgIDText
= load_dynamic_stringW(row
,4);
4637 package
->classes
[index
].ProgIDIndex
=
4638 load_given_progid(package
, package
->classes
[index
].ProgIDText
);
4640 package
->classes
[index
].Description
= load_dynamic_stringW(row
,5);
4642 buffer
= load_dynamic_stringW(row
,6);
4644 package
->classes
[index
].AppIDIndex
=
4645 load_given_appid(package
, buffer
);
4647 package
->classes
[index
].AppIDIndex
= -1;
4648 HeapFree(GetProcessHeap(),0,buffer
);
4650 package
->classes
[index
].FileTypeMask
= load_dynamic_stringW(row
,7);
4652 if (!MSI_RecordIsNull(row
,9))
4655 INT icon_index
= MSI_RecordGetInteger(row
,9);
4656 LPWSTR FileName
= load_dynamic_stringW(row
,8);
4658 static const WCHAR fmt
[] = {'%','s',',','%','i',0};
4660 build_icon_path(package
,FileName
,&FilePath
);
4662 package
->classes
[index
].IconPath
=
4663 HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath
)+5)*
4666 sprintfW(package
->classes
[index
].IconPath
,fmt
,FilePath
,icon_index
);
4668 HeapFree(GetProcessHeap(),0,FilePath
);
4669 HeapFree(GetProcessHeap(),0,FileName
);
4673 buffer
= load_dynamic_stringW(row
,8);
4675 build_icon_path(package
,buffer
,&(package
->classes
[index
].IconPath
));
4676 HeapFree(GetProcessHeap(),0,buffer
);
4679 if (!MSI_RecordIsNull(row
,10))
4681 i
= MSI_RecordGetInteger(row
,10);
4682 if (i
!= MSI_NULL_INTEGER
&& i
> 0 && i
< 4)
4684 static const WCHAR ole2
[] = {'o','l','e','2','.','d','l','l',0};
4685 static const WCHAR ole32
[] = {'o','l','e','3','2','.','d','l','l',0};
4690 package
->classes
[index
].DefInprocHandler
= strdupW(ole2
);
4693 package
->classes
[index
].DefInprocHandler32
= strdupW(ole32
);
4696 package
->classes
[index
].DefInprocHandler
= strdupW(ole2
);
4697 package
->classes
[index
].DefInprocHandler32
= strdupW(ole32
);
4703 package
->classes
[index
].DefInprocHandler32
= load_dynamic_stringW(
4705 reduce_to_longfilename(package
->classes
[index
].DefInprocHandler32
);
4708 buffer
= load_dynamic_stringW(row
,11);
4709 deformat_string(package
,buffer
,&package
->classes
[index
].Argument
);
4710 HeapFree(GetProcessHeap(),0,buffer
);
4712 buffer
= load_dynamic_stringW(row
,12);
4713 package
->classes
[index
].FeatureIndex
= get_loaded_feature(package
,buffer
);
4714 HeapFree(GetProcessHeap(),0,buffer
);
4716 package
->classes
[index
].Attributes
= MSI_RecordGetInteger(row
,13);
4722 * the Class table has 3 primary keys. Generally it is only
4723 * referenced through the first CLSID key. However when loading
4724 * all of the classes we need to make sure we do not ignore rows
4725 * with other Context and ComponentIndexs
4727 static INT
load_given_class(MSIPACKAGE
*package
, LPCWSTR classid
)
4732 static const WCHAR ExecSeqQuery
[] =
4733 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4734 '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ',
4735 '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0};
4741 /* check for classes already loaded */
4742 for (i
= 0; i
< package
->loaded_classes
; i
++)
4743 if (strcmpiW(package
->classes
[i
].CLSID
,classid
)==0)
4745 TRACE("found class %s at index %i\n",debugstr_w(classid
), i
);
4749 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, classid
);
4753 rc
= load_class(package
, row
);
4754 msiobj_release(&row
->hdr
);
4759 static INT
load_given_extension(MSIPACKAGE
*package
, LPCWSTR extension
);
4761 static INT
load_mime(MSIPACKAGE
* package
, MSIRECORD
*row
)
4763 DWORD index
= package
->loaded_mimes
;
4767 /* fill in the data */
4769 package
->loaded_mimes
++;
4770 if (package
->loaded_mimes
== 1)
4771 package
->mimes
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIMIME
));
4773 package
->mimes
= HeapReAlloc(GetProcessHeap(),0,
4774 package
->mimes
, package
->loaded_mimes
*
4777 memset(&package
->mimes
[index
],0,sizeof(MSIMIME
));
4779 package
->mimes
[index
].ContentType
= load_dynamic_stringW(row
,1);
4780 TRACE("loading mime %s\n",debugstr_w(package
->mimes
[index
].ContentType
));
4782 buffer
= load_dynamic_stringW(row
,2);
4783 package
->mimes
[index
].ExtensionIndex
= load_given_extension(package
,
4785 HeapFree(GetProcessHeap(),0,buffer
);
4787 sz
= IDENTIFIER_SIZE
;
4788 MSI_RecordGetStringW(row
,3,package
->mimes
[index
].CLSID
,&sz
);
4789 package
->mimes
[index
].ClassIndex
= load_given_class(package
,
4790 package
->mimes
[index
].CLSID
);
4795 static INT
load_given_mime(MSIPACKAGE
*package
, LPCWSTR mime
)
4800 static const WCHAR ExecSeqQuery
[] =
4801 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4802 '`','M','I','M','E','`',' ','W','H','E','R','E',' ',
4803 '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ',
4804 '\'','%','s','\'',0};
4809 /* check for mime already loaded */
4810 for (i
= 0; i
< package
->loaded_mimes
; i
++)
4811 if (strcmpiW(package
->mimes
[i
].ContentType
,mime
)==0)
4813 TRACE("found mime %s at index %i\n",debugstr_w(mime
), i
);
4817 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, mime
);
4821 rc
= load_mime(package
, row
);
4822 msiobj_release(&row
->hdr
);
4827 static INT
load_extension(MSIPACKAGE
* package
, MSIRECORD
*row
)
4829 DWORD index
= package
->loaded_extensions
;
4833 /* fill in the data */
4835 package
->loaded_extensions
++;
4836 if (package
->loaded_extensions
== 1)
4837 package
->extensions
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIEXTENSION
));
4839 package
->extensions
= HeapReAlloc(GetProcessHeap(),0,
4840 package
->extensions
, package
->loaded_extensions
*
4841 sizeof(MSIEXTENSION
));
4843 memset(&package
->extensions
[index
],0,sizeof(MSIEXTENSION
));
4846 MSI_RecordGetStringW(row
,1,package
->extensions
[index
].Extension
,&sz
);
4847 TRACE("loading extension %s\n",
4848 debugstr_w(package
->extensions
[index
].Extension
));
4850 buffer
= load_dynamic_stringW(row
,2);
4851 package
->extensions
[index
].ComponentIndex
=
4852 get_loaded_component(package
,buffer
);
4853 HeapFree(GetProcessHeap(),0,buffer
);
4855 package
->extensions
[index
].ProgIDText
= load_dynamic_stringW(row
,3);
4856 package
->extensions
[index
].ProgIDIndex
= load_given_progid(package
,
4857 package
->extensions
[index
].ProgIDText
);
4859 buffer
= load_dynamic_stringW(row
,4);
4860 package
->extensions
[index
].MIMEIndex
= load_given_mime(package
,buffer
);
4861 HeapFree(GetProcessHeap(),0,buffer
);
4863 buffer
= load_dynamic_stringW(row
,5);
4864 package
->extensions
[index
].FeatureIndex
=
4865 get_loaded_feature(package
,buffer
);
4866 HeapFree(GetProcessHeap(),0,buffer
);
4872 * While the extension table has 2 primary keys, this function is only looking
4873 * at the Extension key which is what is referenced as a forign key
4875 static INT
load_given_extension(MSIPACKAGE
*package
, LPCWSTR extension
)
4880 static const WCHAR ExecSeqQuery
[] =
4881 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4882 '`','E','x','t','e','n','s','i','o','n','`',' ',
4883 'W','H','E','R','E',' ',
4884 '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ',
4885 '\'','%','s','\'',0};
4890 /* check for extensions already loaded */
4891 for (i
= 0; i
< package
->loaded_extensions
; i
++)
4892 if (strcmpiW(package
->extensions
[i
].Extension
,extension
)==0)
4894 TRACE("extension %s already loaded at %i\n",debugstr_w(extension
),
4899 row
= MSI_QueryGetRecord(package
->db
, ExecSeqQuery
, extension
);
4903 rc
= load_extension(package
, row
);
4904 msiobj_release(&row
->hdr
);
4909 static UINT
iterate_load_verb(MSIRECORD
*row
, LPVOID param
)
4911 MSIPACKAGE
* package
= (MSIPACKAGE
*)param
;
4912 DWORD index
= package
->loaded_verbs
;
4915 /* fill in the data */
4917 package
->loaded_verbs
++;
4918 if (package
->loaded_verbs
== 1)
4919 package
->verbs
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIVERB
));
4921 package
->verbs
= HeapReAlloc(GetProcessHeap(),0,
4922 package
->verbs
, package
->loaded_verbs
* sizeof(MSIVERB
));
4924 memset(&package
->verbs
[index
],0,sizeof(MSIVERB
));
4926 buffer
= load_dynamic_stringW(row
,1);
4927 package
->verbs
[index
].ExtensionIndex
= load_given_extension(package
,buffer
);
4928 if (package
->verbs
[index
].ExtensionIndex
< 0 && buffer
)
4929 ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer
));
4930 HeapFree(GetProcessHeap(),0,buffer
);
4932 package
->verbs
[index
].Verb
= load_dynamic_stringW(row
,2);
4933 TRACE("loading verb %s\n",debugstr_w(package
->verbs
[index
].Verb
));
4934 package
->verbs
[index
].Sequence
= MSI_RecordGetInteger(row
,3);
4936 buffer
= load_dynamic_stringW(row
,4);
4937 deformat_string(package
,buffer
,&package
->verbs
[index
].Command
);
4938 HeapFree(GetProcessHeap(),0,buffer
);
4940 buffer
= load_dynamic_stringW(row
,5);
4941 deformat_string(package
,buffer
,&package
->verbs
[index
].Argument
);
4942 HeapFree(GetProcessHeap(),0,buffer
);
4944 /* assosiate the verb with the correct extension */
4945 if (package
->verbs
[index
].ExtensionIndex
>= 0)
4947 MSIEXTENSION
* extension
= &package
->extensions
[package
->verbs
[index
].
4949 int count
= extension
->VerbCount
;
4952 FIXME("Exceeding max verb count! Increase that limit!!!\n");
4955 extension
->VerbCount
++;
4956 extension
->Verbs
[count
] = index
;
4960 return ERROR_SUCCESS
;
4963 static UINT
iterate_all_classes(MSIRECORD
*rec
, LPVOID param
)
4968 INT component_index
;
4969 MSIPACKAGE
* package
=(MSIPACKAGE
*)param
;
4973 clsid
= load_dynamic_stringW(rec
,1);
4974 context
= load_dynamic_stringW(rec
,2);
4975 buffer
= load_dynamic_stringW(rec
,3);
4976 component_index
= get_loaded_component(package
,buffer
);
4978 for (i
= 0; i
< package
->loaded_classes
; i
++)
4980 if (strcmpiW(clsid
,package
->classes
[i
].CLSID
))
4982 if (strcmpW(context
,package
->classes
[i
].Context
))
4984 if (component_index
== package
->classes
[i
].ComponentIndex
)
4991 HeapFree(GetProcessHeap(),0,buffer
);
4992 HeapFree(GetProcessHeap(),0,clsid
);
4993 HeapFree(GetProcessHeap(),0,context
);
4996 load_class(package
, rec
);
4998 return ERROR_SUCCESS
;
5001 static VOID
load_all_classes(MSIPACKAGE
*package
)
5003 UINT rc
= ERROR_SUCCESS
;
5006 static const WCHAR ExecSeqQuery
[] =
5007 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
5008 '`','C','l','a','s','s','`',0};
5010 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5011 if (rc
!= ERROR_SUCCESS
)
5014 rc
= MSI_IterateRecords(view
, NULL
, iterate_all_classes
, package
);
5015 msiobj_release(&view
->hdr
);
5018 static UINT
iterate_all_extensions(MSIRECORD
*rec
, LPVOID param
)
5022 INT component_index
;
5023 MSIPACKAGE
* package
=(MSIPACKAGE
*)param
;
5027 extension
= load_dynamic_stringW(rec
,1);
5028 buffer
= load_dynamic_stringW(rec
,2);
5029 component_index
= get_loaded_component(package
,buffer
);
5031 for (i
= 0; i
< package
->loaded_extensions
; i
++)
5033 if (strcmpiW(extension
,package
->extensions
[i
].Extension
))
5035 if (component_index
== package
->extensions
[i
].ComponentIndex
)
5042 HeapFree(GetProcessHeap(),0,buffer
);
5043 HeapFree(GetProcessHeap(),0,extension
);
5046 load_extension(package
, rec
);
5048 return ERROR_SUCCESS
;
5051 static VOID
load_all_extensions(MSIPACKAGE
*package
)
5053 UINT rc
= ERROR_SUCCESS
;
5056 static const WCHAR ExecSeqQuery
[] =
5057 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5058 '`','E','x','t','e','n','s','i','o','n','`',0};
5060 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5061 if (rc
!= ERROR_SUCCESS
)
5064 rc
= MSI_IterateRecords(view
, NULL
, iterate_all_extensions
, package
);
5065 msiobj_release(&view
->hdr
);
5068 static UINT
iterate_all_progids(MSIRECORD
*rec
, LPVOID param
)
5071 MSIPACKAGE
* package
=(MSIPACKAGE
*)param
;
5073 buffer
= load_dynamic_stringW(rec
,1);
5074 load_given_progid(package
,buffer
);
5075 HeapFree(GetProcessHeap(),0,buffer
);
5076 return ERROR_SUCCESS
;
5079 static VOID
load_all_progids(MSIPACKAGE
*package
)
5081 UINT rc
= ERROR_SUCCESS
;
5084 static const WCHAR ExecSeqQuery
[] =
5085 {'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ',
5086 'F','R','O','M',' ', '`','P','r','o','g','I','d','`',0};
5088 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5089 if (rc
!= ERROR_SUCCESS
)
5092 rc
= MSI_IterateRecords(view
, NULL
, iterate_all_progids
, package
);
5093 msiobj_release(&view
->hdr
);
5096 static VOID
load_all_verbs(MSIPACKAGE
*package
)
5098 UINT rc
= ERROR_SUCCESS
;
5101 static const WCHAR ExecSeqQuery
[] =
5102 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5103 '`','V','e','r','b','`',0};
5105 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5106 if (rc
!= ERROR_SUCCESS
)
5109 rc
= MSI_IterateRecords(view
, NULL
, iterate_load_verb
, package
);
5110 msiobj_release(&view
->hdr
);
5113 static UINT
iterate_all_mimes(MSIRECORD
*rec
, LPVOID param
)
5116 MSIPACKAGE
* package
=(MSIPACKAGE
*)param
;
5118 buffer
= load_dynamic_stringW(rec
,1);
5119 load_given_mime(package
,buffer
);
5120 HeapFree(GetProcessHeap(),0,buffer
);
5121 return ERROR_SUCCESS
;
5124 static VOID
load_all_mimes(MSIPACKAGE
*package
)
5126 UINT rc
= ERROR_SUCCESS
;
5129 static const WCHAR ExecSeqQuery
[] =
5130 {'S','E','L','E','C','T',' ',
5131 '`','C','o','n','t','e','n','t','T','y','p','e','`',
5132 ' ','F','R','O','M',' ',
5133 '`','M','I','M','E','`',0};
5135 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5136 if (rc
!= ERROR_SUCCESS
)
5139 rc
= MSI_IterateRecords(view
, NULL
, iterate_all_mimes
, package
);
5140 msiobj_release(&view
->hdr
);
5143 static void load_classes_and_such(MSIPACKAGE
*package
)
5145 TRACE("Loading all the class info and related tables\n");
5147 /* check if already loaded */
5148 if (package
->classes
|| package
->extensions
|| package
->progids
||
5149 package
->verbs
|| package
->mimes
)
5152 load_all_classes(package
);
5153 load_all_extensions(package
);
5154 load_all_progids(package
);
5155 /* these loads must come after the other loads */
5156 load_all_verbs(package
);
5157 load_all_mimes(package
);
5160 static void mark_progid_for_install(MSIPACKAGE
* package
, INT index
)
5165 if (index
< 0 || index
>= package
->loaded_progids
)
5168 progid
= &package
->progids
[index
];
5170 if (progid
->InstallMe
== TRUE
)
5173 progid
->InstallMe
= TRUE
;
5175 /* all children if this is a parent also install */
5176 for (i
= 0; i
< package
->loaded_progids
; i
++)
5177 if (package
->progids
[i
].ParentIndex
== index
)
5178 mark_progid_for_install(package
,i
);
5181 static void mark_mime_for_install(MSIPACKAGE
* package
, INT index
)
5185 if (index
< 0 || index
>= package
->loaded_mimes
)
5188 mime
= &package
->mimes
[index
];
5190 if (mime
->InstallMe
== TRUE
)
5193 mime
->InstallMe
= TRUE
;
5196 static UINT
register_appid(MSIPACKAGE
*package
, int appidIndex
, LPCWSTR app
)
5198 static const WCHAR szAppID
[] = { 'A','p','p','I','D',0 };
5202 return ERROR_INVALID_HANDLE
;
5204 RegCreateKeyW(HKEY_CLASSES_ROOT
,szAppID
,&hkey2
);
5205 RegCreateKeyW(hkey2
,package
->appids
[appidIndex
].AppID
,&hkey3
);
5206 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,(LPVOID
)app
,
5207 (strlenW(app
)+1)*sizeof(WCHAR
));
5209 if (package
->appids
[appidIndex
].RemoteServerName
)
5212 static const WCHAR szRemoteServerName
[] =
5213 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',
5216 size
= (strlenW(package
->appids
[appidIndex
].RemoteServerName
)+1) *
5219 RegSetValueExW(hkey3
,szRemoteServerName
,0,REG_SZ
,
5220 (LPVOID
)package
->appids
[appidIndex
].RemoteServerName
,
5224 if (package
->appids
[appidIndex
].LocalServer
)
5226 static const WCHAR szLocalService
[] =
5227 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
5229 size
= (strlenW(package
->appids
[appidIndex
].LocalServer
)+1) *
5232 RegSetValueExW(hkey3
,szLocalService
,0,REG_SZ
,
5233 (LPVOID
)package
->appids
[appidIndex
].LocalServer
,size
);
5236 if (package
->appids
[appidIndex
].ServiceParameters
)
5238 static const WCHAR szService
[] =
5239 {'S','e','r','v','i','c','e',
5240 'P','a','r','a','m','e','t','e','r','s',0};
5242 size
= (strlenW(package
->appids
[appidIndex
].ServiceParameters
)+1) *
5244 RegSetValueExW(hkey3
,szService
,0,REG_SZ
,
5245 (LPVOID
)package
->appids
[appidIndex
].ServiceParameters
,
5249 if (package
->appids
[appidIndex
].DllSurrogate
)
5251 static const WCHAR szDLL
[] =
5252 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
5254 size
= (strlenW(package
->appids
[appidIndex
].DllSurrogate
)+1) *
5256 RegSetValueExW(hkey3
,szDLL
,0,REG_SZ
,
5257 (LPVOID
)package
->appids
[appidIndex
].DllSurrogate
,size
);
5260 if (package
->appids
[appidIndex
].ActivateAtStorage
)
5262 static const WCHAR szActivate
[] =
5263 {'A','c','t','i','v','a','t','e','A','s',
5264 'S','t','o','r','a','g','e',0};
5265 static const WCHAR szY
[] = {'Y',0};
5267 RegSetValueExW(hkey3
,szActivate
,0,REG_SZ
,(LPVOID
)szY
,4);
5270 if (package
->appids
[appidIndex
].RunAsInteractiveUser
)
5272 static const WCHAR szRunAs
[] = {'R','u','n','A','s',0};
5273 static const WCHAR szUser
[] =
5274 {'I','n','t','e','r','a','c','t','i','v','e',' ',
5277 RegSetValueExW(hkey3
,szRunAs
,0,REG_SZ
,(LPVOID
)szUser
,sizeof(szUser
));
5282 return ERROR_SUCCESS
;
5285 static UINT
ACTION_RegisterClassInfo(MSIPACKAGE
*package
)
5288 * Again I am assuming the words, "Whose key file represents" when referring
5289 * to a Component as to meaning that Components KeyPath file
5294 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
5295 static const WCHAR szProgID
[] = { 'P','r','o','g','I','D',0 };
5296 static const WCHAR szVIProgID
[] = { 'V','e','r','s','i','o','n','I','n','d','e','p','e','n','d','e','n','t','P','r','o','g','I','D',0 };
5297 static const WCHAR szAppID
[] = { 'A','p','p','I','D',0 };
5298 static const WCHAR szSpace
[] = {' ',0};
5299 static const WCHAR szInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
5300 static const WCHAR szFileType_fmt
[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
5301 HKEY hkey
,hkey2
,hkey3
;
5302 BOOL install_on_demand
= FALSE
;
5306 return ERROR_INVALID_HANDLE
;
5308 load_classes_and_such(package
);
5309 rc
= RegCreateKeyW(HKEY_CLASSES_ROOT
,szCLSID
,&hkey
);
5310 if (rc
!= ERROR_SUCCESS
)
5311 return ERROR_FUNCTION_FAILED
;
5313 /* install_on_demand should be set if OLE supports install on demand OLE
5314 * servers. For now i am defaulting to FALSE because i do not know how to
5315 * check, and i am told our builtin OLE does not support it
5318 for (i
= 0; i
< package
->loaded_classes
; i
++)
5324 if (package
->classes
[i
].ComponentIndex
< 0)
5329 index
= package
->classes
[i
].ComponentIndex
;
5330 f_index
= package
->classes
[i
].FeatureIndex
;
5333 * yes. MSDN says that these are based on _Feature_ not on
5334 * Component. So verify the feature is to be installed
5336 if ((!ACTION_VerifyFeatureForAction(package
, f_index
,
5337 INSTALLSTATE_LOCAL
)) &&
5338 !(install_on_demand
&& ACTION_VerifyFeatureForAction(package
,
5339 f_index
, INSTALLSTATE_ADVERTISED
)))
5341 TRACE("Skipping class %s reg due to disabled feature %s\n",
5342 debugstr_w(package
->classes
[i
].CLSID
),
5343 debugstr_w(package
->features
[f_index
].Feature
));
5348 TRACE("Registering index %i class %s\n",i
,
5349 debugstr_w(package
->classes
[i
].CLSID
));
5351 package
->classes
[i
].Installed
= TRUE
;
5352 if (package
->classes
[i
].ProgIDIndex
>= 0)
5353 mark_progid_for_install(package
, package
->classes
[i
].ProgIDIndex
);
5355 RegCreateKeyW(hkey
,package
->classes
[i
].CLSID
,&hkey2
);
5357 if (package
->classes
[i
].Description
)
5358 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)package
->classes
[i
].
5359 Description
, (strlenW(package
->classes
[i
].
5360 Description
)+1)*sizeof(WCHAR
));
5362 RegCreateKeyW(hkey2
,package
->classes
[i
].Context
,&hkey3
);
5363 index
= get_loaded_file(package
,package
->components
[index
].KeyPath
);
5366 /* the context server is a short path name
5367 * except for if it is InprocServer32...
5369 if (strcmpiW(package
->classes
[i
].Context
,szInprocServer32
)!=0)
5372 sz
= GetShortPathNameW(package
->files
[index
].TargetPath
, NULL
, 0);
5375 ERR("Unable to find short path for CLSID COM Server\n");
5380 size
= sz
* sizeof(WCHAR
);
5382 if (package
->classes
[i
].Argument
)
5384 size
+= strlenW(package
->classes
[i
].Argument
) *
5386 size
+= sizeof(WCHAR
);
5389 argument
= HeapAlloc(GetProcessHeap(), 0, size
+ sizeof(WCHAR
));
5390 GetShortPathNameW(package
->files
[index
].TargetPath
, argument
,
5393 if (package
->classes
[i
].Argument
)
5395 strcatW(argument
,szSpace
);
5396 strcatW(argument
,package
->classes
[i
].Argument
);
5402 size
= lstrlenW(package
->files
[index
].TargetPath
) * sizeof(WCHAR
);
5404 if (package
->classes
[i
].Argument
)
5406 size
+= strlenW(package
->classes
[i
].Argument
) * sizeof(WCHAR
);
5407 size
+= sizeof(WCHAR
);
5410 argument
= HeapAlloc(GetProcessHeap(), 0, size
+ sizeof(WCHAR
));
5411 strcpyW(argument
, package
->files
[index
].TargetPath
);
5413 if (package
->classes
[i
].Argument
)
5415 strcatW(argument
,szSpace
);
5416 strcatW(argument
,package
->classes
[i
].Argument
);
5422 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
, (LPVOID
)argument
, size
);
5423 HeapFree(GetProcessHeap(),0,argument
);
5428 if (package
->classes
[i
].ProgIDIndex
>= 0 ||
5429 package
->classes
[i
].ProgIDText
)
5433 if (package
->classes
[i
].ProgIDIndex
>= 0)
5434 progid
= package
->progids
[
5435 package
->classes
[i
].ProgIDIndex
].ProgID
;
5437 progid
= package
->classes
[i
].ProgIDText
;
5439 RegCreateKeyW(hkey2
,szProgID
,&hkey3
);
5440 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,(LPVOID
)progid
,
5441 (strlenW(progid
)+1) *sizeof(WCHAR
));
5444 if (package
->classes
[i
].ProgIDIndex
>= 0 &&
5445 package
->progids
[package
->classes
[i
].ProgIDIndex
].
5446 VersionIndIndex
>= 0)
5448 LPWSTR viprogid
= strdupW(package
->progids
[package
->progids
[
5449 package
->classes
[i
].ProgIDIndex
].VersionIndIndex
].
5451 RegCreateKeyW(hkey2
,szVIProgID
,&hkey3
);
5452 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,(LPVOID
)viprogid
,
5453 (strlenW(viprogid
)+1) *sizeof(WCHAR
));
5455 HeapFree(GetProcessHeap(), 0, viprogid
);
5459 if (package
->classes
[i
].AppIDIndex
>= 0)
5461 RegSetValueExW(hkey2
,szAppID
,0,REG_SZ
,
5462 (LPVOID
)package
->appids
[package
->classes
[i
].AppIDIndex
].AppID
,
5463 (strlenW(package
->appids
[package
->classes
[i
].AppIDIndex
].AppID
)+1)
5466 register_appid(package
,package
->classes
[i
].AppIDIndex
,
5467 package
->classes
[i
].Description
);
5470 if (package
->classes
[i
].IconPath
)
5472 static const WCHAR szDefaultIcon
[] =
5473 {'D','e','f','a','u','l','t','I','c','o','n',0};
5475 RegCreateKeyW(hkey2
,szDefaultIcon
,&hkey3
);
5477 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,
5478 (LPVOID
)package
->classes
[i
].IconPath
,
5479 (strlenW(package
->classes
[i
].IconPath
)+1) *
5485 if (package
->classes
[i
].DefInprocHandler
)
5487 static const WCHAR szInproc
[] =
5488 {'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
5490 size
= (strlenW(package
->classes
[i
].DefInprocHandler
) + 1) *
5492 RegCreateKeyW(hkey2
,szInproc
,&hkey3
);
5493 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,
5494 (LPVOID
)package
->classes
[i
].DefInprocHandler
, size
);
5498 if (package
->classes
[i
].DefInprocHandler32
)
5500 static const WCHAR szInproc32
[] =
5501 {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',
5503 size
= (strlenW(package
->classes
[i
].DefInprocHandler32
) + 1) *
5506 RegCreateKeyW(hkey2
,szInproc32
,&hkey3
);
5507 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,
5508 (LPVOID
)package
->classes
[i
].DefInprocHandler32
,size
);
5514 /* if there is a FileTypeMask, register the FileType */
5515 if (package
->classes
[i
].FileTypeMask
)
5520 ptr
= package
->classes
[i
].FileTypeMask
;
5523 ptr2
= strchrW(ptr
,';');
5526 keyname
= HeapAlloc(GetProcessHeap(),0,(strlenW(szFileType_fmt
)+
5527 strlenW(package
->classes
[i
].CLSID
) + 4)
5529 sprintfW(keyname
,szFileType_fmt
, package
->classes
[i
].CLSID
,
5532 RegCreateKeyW(HKEY_CLASSES_ROOT
,keyname
,&hkey2
);
5533 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
, (LPVOID
)ptr
,
5534 strlenW(ptr
)*sizeof(WCHAR
));
5536 HeapFree(GetProcessHeap(), 0, keyname
);
5547 uirow
= MSI_CreateRecord(1);
5549 MSI_RecordSetStringW(uirow
,1,package
->classes
[i
].CLSID
);
5550 ui_actiondata(package
,szRegisterClassInfo
,uirow
);
5551 msiobj_release(&uirow
->hdr
);
5558 static UINT
register_progid_base(MSIPACKAGE
* package
, MSIPROGID
* progid
,
5561 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
5562 static const WCHAR szDefaultIcon
[] =
5563 {'D','e','f','a','u','l','t','I','c','o','n',0};
5566 RegCreateKeyW(HKEY_CLASSES_ROOT
,progid
->ProgID
,&hkey
);
5568 if (progid
->Description
)
5570 RegSetValueExW(hkey
,NULL
,0,REG_SZ
,
5571 (LPVOID
)progid
->Description
,
5572 (strlenW(progid
->Description
)+1) *
5576 if (progid
->ClassIndex
>= 0)
5578 RegCreateKeyW(hkey
,szCLSID
,&hkey2
);
5579 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,
5580 (LPVOID
)package
->classes
[progid
->ClassIndex
].CLSID
,
5581 (strlenW(package
->classes
[progid
->ClassIndex
].CLSID
)+1)
5585 strcpyW(clsid
,package
->classes
[progid
->ClassIndex
].CLSID
);
5591 FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
5594 if (progid
->IconPath
)
5596 RegCreateKeyW(hkey
,szDefaultIcon
,&hkey2
);
5598 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)progid
->IconPath
,
5599 (strlenW(progid
->IconPath
)+1) * sizeof(WCHAR
));
5602 return ERROR_SUCCESS
;
5605 static UINT
register_progid(MSIPACKAGE
*package
, MSIPROGID
* progid
,
5608 UINT rc
= ERROR_SUCCESS
;
5610 if (progid
->ParentIndex
< 0)
5611 rc
= register_progid_base(package
, progid
, clsid
);
5616 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
5617 static const WCHAR szDefaultIcon
[] =
5618 {'D','e','f','a','u','l','t','I','c','o','n',0};
5619 static const WCHAR szCurVer
[] =
5620 {'C','u','r','V','e','r',0};
5622 /* check if already registered */
5623 RegCreateKeyExW(HKEY_CLASSES_ROOT
, progid
->ProgID
, 0, NULL
, 0,
5624 KEY_ALL_ACCESS
, NULL
, &hkey
, &disp
);
5625 if (disp
== REG_OPENED_EXISTING_KEY
)
5627 TRACE("Key already registered\n");
5632 TRACE("Registering Parent %s index %i\n",
5633 debugstr_w(package
->progids
[progid
->ParentIndex
].ProgID
),
5634 progid
->ParentIndex
);
5635 rc
= register_progid(package
,&package
->progids
[progid
->ParentIndex
],
5638 /* clsid is same as parent */
5639 RegCreateKeyW(hkey
,szCLSID
,&hkey2
);
5640 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)clsid
, (strlenW(clsid
)+1) *
5646 if (progid
->Description
)
5648 RegSetValueExW(hkey
,NULL
,0,REG_SZ
,(LPVOID
)progid
->Description
,
5649 (strlenW(progid
->Description
)+1) * sizeof(WCHAR
));
5652 if (progid
->IconPath
)
5654 RegCreateKeyW(hkey
,szDefaultIcon
,&hkey2
);
5655 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)progid
->IconPath
,
5656 (strlenW(progid
->IconPath
)+1) * sizeof(WCHAR
));
5660 /* write out the current version */
5661 if (progid
->CurVerIndex
>= 0)
5663 RegCreateKeyW(hkey
,szCurVer
,&hkey2
);
5664 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,
5665 (LPVOID
)package
->progids
[progid
->CurVerIndex
].ProgID
,
5666 (strlenW(package
->progids
[progid
->CurVerIndex
].ProgID
)+1) *
5676 static UINT
ACTION_RegisterProgIdInfo(MSIPACKAGE
*package
)
5682 return ERROR_INVALID_HANDLE
;
5684 load_classes_and_such(package
);
5686 for (i
= 0; i
< package
->loaded_progids
; i
++)
5688 WCHAR clsid
[0x1000];
5690 /* check if this progid is to be installed */
5691 package
->progids
[i
].InstallMe
= ((package
->progids
[i
].InstallMe
) ||
5692 (package
->progids
[i
].ClassIndex
>= 0 &&
5693 package
->classes
[package
->progids
[i
].ClassIndex
].Installed
));
5695 if (!package
->progids
[i
].InstallMe
)
5697 TRACE("progid %s not scheduled to be installed\n",
5698 debugstr_w(package
->progids
[i
].ProgID
));
5702 TRACE("Registering progid %s index %i\n",
5703 debugstr_w(package
->progids
[i
].ProgID
), i
);
5705 register_progid(package
,&package
->progids
[i
],clsid
);
5707 uirow
= MSI_CreateRecord(1);
5708 MSI_RecordSetStringW(uirow
,1,package
->progids
[i
].ProgID
);
5709 ui_actiondata(package
,szRegisterProgIdInfo
,uirow
);
5710 msiobj_release(&uirow
->hdr
);
5713 return ERROR_SUCCESS
;
5716 static UINT
build_icon_path(MSIPACKAGE
*package
, LPCWSTR icon_name
,
5720 LPWSTR SystemFolder
;
5724 static const WCHAR szInstaller
[] =
5725 {'M','i','c','r','o','s','o','f','t','\\',
5726 'I','n','s','t','a','l','l','e','r','\\',0};
5727 static const WCHAR szFolder
[] =
5728 {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
5730 ProductCode
= load_dynamic_property(package
,szProductCode
,&rc
);
5734 SystemFolder
= load_dynamic_property(package
,szFolder
,NULL
);
5736 dest
= build_directory_name(3, SystemFolder
, szInstaller
, ProductCode
);
5738 create_full_pathW(dest
);
5740 *FilePath
= build_directory_name(2, dest
, icon_name
);
5742 HeapFree(GetProcessHeap(),0,SystemFolder
);
5743 HeapFree(GetProcessHeap(),0,ProductCode
);
5744 HeapFree(GetProcessHeap(),0,dest
);
5745 return ERROR_SUCCESS
;
5748 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
5752 MSIRECORD
* row
= 0;
5753 static const WCHAR Query
[] =
5754 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5755 '`','S','h','o','r','t','c','u','t','`',0};
5761 return ERROR_INVALID_HANDLE
;
5763 res
= CoInitialize( NULL
);
5766 ERR("CoInitialize failed\n");
5767 return ERROR_FUNCTION_FAILED
;
5770 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
5771 if (rc
!= ERROR_SUCCESS
)
5772 return ERROR_SUCCESS
;
5774 rc
= MSI_ViewExecute(view
, 0);
5775 if (rc
!= ERROR_SUCCESS
)
5777 MSI_ViewClose(view
);
5778 msiobj_release(&view
->hdr
);
5784 LPWSTR target_file
, target_folder
;
5785 WCHAR buffer
[0x100];
5788 static const WCHAR szlnk
[]={'.','l','n','k',0};
5790 rc
= MSI_ViewFetch(view
,&row
);
5791 if (rc
!= ERROR_SUCCESS
)
5798 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
5800 index
= get_loaded_component(package
,buffer
);
5804 msiobj_release(&row
->hdr
);
5808 if (!ACTION_VerifyComponentForAction(package
, index
,
5809 INSTALLSTATE_LOCAL
))
5811 TRACE("Skipping shortcut creation due to disabled component\n");
5812 msiobj_release(&row
->hdr
);
5814 package
->components
[index
].Action
=
5815 package
->components
[index
].Installed
;
5820 package
->components
[index
].Action
= INSTALLSTATE_LOCAL
;
5822 ui_actiondata(package
,szCreateShortcuts
,row
);
5824 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
5825 &IID_IShellLinkW
, (LPVOID
*) &sl
);
5829 ERR("Is IID_IShellLink\n");
5830 msiobj_release(&row
->hdr
);
5834 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
5837 ERR("Is IID_IPersistFile\n");
5838 msiobj_release(&row
->hdr
);
5843 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
5844 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,NULL
);
5846 /* may be needed because of a bug somehwere else */
5847 create_full_pathW(target_folder
);
5850 MSI_RecordGetStringW(row
,3,buffer
,&sz
);
5851 reduce_to_longfilename(buffer
);
5852 if (!strchrW(buffer
,'.') || strcmpiW(strchrW(buffer
,'.'),szlnk
))
5853 strcatW(buffer
,szlnk
);
5854 target_file
= build_directory_name(2, target_folder
, buffer
);
5855 HeapFree(GetProcessHeap(),0,target_folder
);
5858 MSI_RecordGetStringW(row
,5,buffer
,&sz
);
5859 if (strchrW(buffer
,'['))
5862 deformat_string(package
,buffer
,&deformated
);
5863 IShellLinkW_SetPath(sl
,deformated
);
5864 HeapFree(GetProcessHeap(),0,deformated
);
5869 FIXME("poorly handled shortcut format, advertised shortcut\n");
5870 keypath
= strdupW(package
->components
[index
].FullKeypath
);
5871 IShellLinkW_SetPath(sl
,keypath
);
5872 HeapFree(GetProcessHeap(),0,keypath
);
5875 if (!MSI_RecordIsNull(row
,6))
5879 MSI_RecordGetStringW(row
,6,buffer
,&sz
);
5880 deformat_string(package
,buffer
,&deformated
);
5881 IShellLinkW_SetArguments(sl
,deformated
);
5882 HeapFree(GetProcessHeap(),0,deformated
);
5885 if (!MSI_RecordIsNull(row
,7))
5888 deformated
= load_dynamic_stringW(row
,7);
5889 IShellLinkW_SetDescription(sl
,deformated
);
5890 HeapFree(GetProcessHeap(),0,deformated
);
5893 if (!MSI_RecordIsNull(row
,8))
5894 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
5896 if (!MSI_RecordIsNull(row
,9))
5902 MSI_RecordGetStringW(row
,9,buffer
,&sz
);
5904 build_icon_path(package
,buffer
,&Path
);
5905 index
= MSI_RecordGetInteger(row
,10);
5907 IShellLinkW_SetIconLocation(sl
,Path
,index
);
5908 HeapFree(GetProcessHeap(),0,Path
);
5911 if (!MSI_RecordIsNull(row
,11))
5912 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
5914 if (!MSI_RecordIsNull(row
,12))
5918 MSI_RecordGetStringW(row
,12,buffer
,&sz
);
5919 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, NULL
);
5920 IShellLinkW_SetWorkingDirectory(sl
,Path
);
5921 HeapFree(GetProcessHeap(), 0, Path
);
5924 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
5925 IPersistFile_Save(pf
,target_file
,FALSE
);
5927 HeapFree(GetProcessHeap(),0,target_file
);
5929 IPersistFile_Release( pf
);
5930 IShellLinkW_Release( sl
);
5932 msiobj_release(&row
->hdr
);
5934 MSI_ViewClose(view
);
5935 msiobj_release(&view
->hdr
);
5945 * 99% of the work done here is only done for
5946 * advertised installs. However this is where the
5947 * Icon table is processed and written out
5948 * so that is what I am going to do here.
5950 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
5954 MSIRECORD
* row
= 0;
5955 static const WCHAR Query
[]=
5956 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5957 '`','I','c','o','n','`',0};
5959 /* for registry stuff */
5963 static const WCHAR szProductName
[] =
5964 {'P','r','o','d','u','c','t','N','a','m','e',0};
5965 static const WCHAR szPackageCode
[] =
5966 {'P','a','c','k','a','g','e','C','o','d','e',0};
5967 static const WCHAR szLanguage
[] =
5968 {'L','a','n','g','u','a','g','e',0};
5969 static const WCHAR szProductLanguage
[] =
5970 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
5971 static const WCHAR szProductIcon
[] =
5972 {'P','r','o','d','u','c','t','I','c','o','n',0};
5973 static const WCHAR szARPProductIcon
[] =
5974 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
5978 MSIHANDLE hDb
, hSumInfo
;
5981 return ERROR_INVALID_HANDLE
;
5983 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
5984 if (rc
!= ERROR_SUCCESS
)
5987 rc
= MSI_ViewExecute(view
, 0);
5988 if (rc
!= ERROR_SUCCESS
)
5990 MSI_ViewClose(view
);
5991 msiobj_release(&view
->hdr
);
5998 WCHAR
*FilePath
=NULL
;
5999 WCHAR
*FileName
=NULL
;
6002 rc
= MSI_ViewFetch(view
,&row
);
6003 if (rc
!= ERROR_SUCCESS
)
6009 FileName
= load_dynamic_stringW(row
,1);
6012 ERR("Unable to get FileName\n");
6013 msiobj_release(&row
->hdr
);
6017 build_icon_path(package
,FileName
,&FilePath
);
6019 HeapFree(GetProcessHeap(),0,FileName
);
6021 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
6023 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
6024 FILE_ATTRIBUTE_NORMAL
, NULL
);
6026 if (the_file
== INVALID_HANDLE_VALUE
)
6028 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
6029 msiobj_release(&row
->hdr
);
6030 HeapFree(GetProcessHeap(),0,FilePath
);
6038 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
6039 if (rc
!= ERROR_SUCCESS
)
6041 ERR("Failed to get stream\n");
6042 CloseHandle(the_file
);
6043 DeleteFileW(FilePath
);
6046 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
6047 } while (sz
== 1024);
6049 HeapFree(GetProcessHeap(),0,FilePath
);
6051 CloseHandle(the_file
);
6052 msiobj_release(&row
->hdr
);
6054 MSI_ViewClose(view
);
6055 msiobj_release(&view
->hdr
);
6058 /* ok there is a lot more done here but i need to figure out what */
6059 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
6063 rc
= MSIREG_OpenProductsKey(productcode
,&hkey
,TRUE
);
6064 if (rc
!= ERROR_SUCCESS
)
6067 rc
= MSIREG_OpenUserProductsKey(productcode
,&hukey
,TRUE
);
6068 if (rc
!= ERROR_SUCCESS
)
6072 buffer
= load_dynamic_property(package
,szProductName
,NULL
);
6073 size
= strlenW(buffer
)*sizeof(WCHAR
);
6074 RegSetValueExW(hukey
,szProductName
,0,REG_SZ
, (LPSTR
)buffer
,size
);
6075 HeapFree(GetProcessHeap(),0,buffer
);
6077 buffer
= load_dynamic_property(package
,szProductLanguage
,NULL
);
6078 size
= sizeof(DWORD
);
6079 langid
= atoiW(buffer
);
6080 RegSetValueExW(hukey
,szLanguage
,0,REG_DWORD
, (BYTE
*)&langid
,size
);
6082 buffer
= load_dynamic_property(package
,szARPProductIcon
,NULL
);
6086 build_icon_path(package
,buffer
,&path
);
6087 size
= strlenW(path
) * sizeof(WCHAR
);
6088 RegSetValueExW(hukey
,szProductIcon
,0,REG_SZ
, (BYTE
*)path
,size
);
6091 FIXME("Need to write more keys to the user registry\n");
6093 hDb
= alloc_msihandle( &package
->db
->hdr
);
6094 rc
= MsiGetSummaryInformationW(hDb
, NULL
, 0, &hSumInfo
);
6095 MsiCloseHandle(hDb
);
6096 if (rc
== ERROR_SUCCESS
)
6098 WCHAR guidbuffer
[0x200];
6100 rc
= MsiSummaryInfoGetPropertyW(hSumInfo
, 9, NULL
, NULL
, NULL
,
6102 if (rc
== ERROR_SUCCESS
)
6104 WCHAR squashed
[GUID_SIZE
];
6105 /* for now we only care about the first guid */
6106 LPWSTR ptr
= strchrW(guidbuffer
,';');
6108 squash_guid(guidbuffer
,squashed
);
6109 size
= strlenW(squashed
)*sizeof(WCHAR
);
6110 RegSetValueExW(hukey
,szPackageCode
,0,REG_SZ
, (LPSTR
)squashed
,
6115 ERR("Unable to query Revision_Number... \n");
6118 MsiCloseHandle(hSumInfo
);
6122 ERR("Unable to open Summary Information\n");
6128 HeapFree(GetProcessHeap(),0,productcode
);
6135 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
6139 MSIRECORD
* row
= 0;
6140 static const WCHAR ExecSeqQuery
[] =
6141 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6142 '`','I','n','i','F','i','l','e','`',0};
6143 static const WCHAR szWindowsFolder
[] =
6144 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
6146 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
6147 if (rc
!= ERROR_SUCCESS
)
6149 TRACE("no IniFile table\n");
6150 return ERROR_SUCCESS
;
6153 rc
= MSI_ViewExecute(view
, 0);
6154 if (rc
!= ERROR_SUCCESS
)
6156 MSI_ViewClose(view
);
6157 msiobj_release(&view
->hdr
);
6163 LPWSTR component
,filename
,dirproperty
,section
,key
,value
,identifier
;
6164 LPWSTR deformated_section
, deformated_key
, deformated_value
;
6165 LPWSTR folder
, fullname
= NULL
;
6167 INT component_index
,action
;
6169 rc
= MSI_ViewFetch(view
,&row
);
6170 if (rc
!= ERROR_SUCCESS
)
6176 component
= load_dynamic_stringW(row
, 8);
6177 component_index
= get_loaded_component(package
,component
);
6178 HeapFree(GetProcessHeap(),0,component
);
6180 if (!ACTION_VerifyComponentForAction(package
, component_index
,
6181 INSTALLSTATE_LOCAL
))
6183 TRACE("Skipping ini file due to disabled component\n");
6184 msiobj_release(&row
->hdr
);
6186 package
->components
[component_index
].Action
=
6187 package
->components
[component_index
].Installed
;
6192 package
->components
[component_index
].Action
= INSTALLSTATE_LOCAL
;
6194 identifier
= load_dynamic_stringW(row
,1);
6195 filename
= load_dynamic_stringW(row
,2);
6196 dirproperty
= load_dynamic_stringW(row
,3);
6197 section
= load_dynamic_stringW(row
,4);
6198 key
= load_dynamic_stringW(row
,5);
6199 value
= load_dynamic_stringW(row
,6);
6200 action
= MSI_RecordGetInteger(row
,7);
6202 deformat_string(package
,section
,&deformated_section
);
6203 deformat_string(package
,key
,&deformated_key
);
6204 deformat_string(package
,value
,&deformated_value
);
6208 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, NULL
);
6210 folder
= load_dynamic_property(package
,dirproperty
,NULL
);
6213 folder
= load_dynamic_property(package
, szWindowsFolder
, NULL
);
6217 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
6221 fullname
= build_directory_name(3, folder
, filename
, NULL
);
6225 TRACE("Adding value %s to section %s in %s\n",
6226 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
6227 debugstr_w(fullname
));
6228 WritePrivateProfileStringW(deformated_section
, deformated_key
,
6229 deformated_value
, fullname
);
6231 else if (action
== 1)
6234 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
6235 returned
, 10, fullname
);
6236 if (returned
[0] == 0)
6238 TRACE("Adding value %s to section %s in %s\n",
6239 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
6240 debugstr_w(fullname
));
6242 WritePrivateProfileStringW(deformated_section
, deformated_key
,
6243 deformated_value
, fullname
);
6246 else if (action
== 3)
6248 FIXME("Append to existing section not yet implemented\n");
6251 uirow
= MSI_CreateRecord(4);
6252 MSI_RecordSetStringW(uirow
,1,identifier
);
6253 MSI_RecordSetStringW(uirow
,2,deformated_section
);
6254 MSI_RecordSetStringW(uirow
,3,deformated_key
);
6255 MSI_RecordSetStringW(uirow
,4,deformated_value
);
6256 ui_actiondata(package
,szWriteIniValues
,uirow
);
6257 msiobj_release( &uirow
->hdr
);
6259 HeapFree(GetProcessHeap(),0,identifier
);
6260 HeapFree(GetProcessHeap(),0,fullname
);
6261 HeapFree(GetProcessHeap(),0,filename
);
6262 HeapFree(GetProcessHeap(),0,key
);
6263 HeapFree(GetProcessHeap(),0,value
);
6264 HeapFree(GetProcessHeap(),0,section
);
6265 HeapFree(GetProcessHeap(),0,dirproperty
);
6266 HeapFree(GetProcessHeap(),0,folder
);
6267 HeapFree(GetProcessHeap(),0,deformated_key
);
6268 HeapFree(GetProcessHeap(),0,deformated_value
);
6269 HeapFree(GetProcessHeap(),0,deformated_section
);
6270 msiobj_release(&row
->hdr
);
6272 MSI_ViewClose(view
);
6273 msiobj_release(&view
->hdr
);
6277 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
6281 MSIRECORD
* row
= 0;
6282 static const WCHAR ExecSeqQuery
[] =
6283 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6284 '`','S','e','l','f','R','e','g','`',0};
6286 static const WCHAR ExeStr
[] =
6287 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
6288 static const WCHAR close
[] = {'\"',0};
6290 PROCESS_INFORMATION info
;
6293 memset(&si
,0,sizeof(STARTUPINFOW
));
6295 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
6296 if (rc
!= ERROR_SUCCESS
)
6298 TRACE("no SelfReg table\n");
6299 return ERROR_SUCCESS
;
6302 rc
= MSI_ViewExecute(view
, 0);
6303 if (rc
!= ERROR_SUCCESS
)
6305 MSI_ViewClose(view
);
6306 msiobj_release(&view
->hdr
);
6316 rc
= MSI_ViewFetch(view
,&row
);
6317 if (rc
!= ERROR_SUCCESS
)
6323 filename
= load_dynamic_stringW(row
,1);
6324 index
= get_loaded_file(package
,filename
);
6328 ERR("Unable to find file id %s\n",debugstr_w(filename
));
6329 HeapFree(GetProcessHeap(),0,filename
);
6330 msiobj_release(&row
->hdr
);
6333 HeapFree(GetProcessHeap(),0,filename
);
6335 len
= strlenW(ExeStr
);
6336 len
+= strlenW(package
->files
[index
].TargetPath
);
6339 filename
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
6340 strcpyW(filename
,ExeStr
);
6341 strcatW(filename
,package
->files
[index
].TargetPath
);
6342 strcatW(filename
,close
);
6344 TRACE("Registering %s\n",debugstr_w(filename
));
6345 brc
= CreateProcessW(NULL
, filename
, NULL
, NULL
, FALSE
, 0, NULL
,
6346 c_colon
, &si
, &info
);
6349 msi_dialog_check_messages(info
.hProcess
);
6351 HeapFree(GetProcessHeap(),0,filename
);
6352 msiobj_release(&row
->hdr
);
6354 MSI_ViewClose(view
);
6355 msiobj_release(&view
->hdr
);
6359 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
6368 return ERROR_INVALID_HANDLE
;
6370 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
6374 rc
= MSIREG_OpenFeaturesKey(productcode
,&hkey
,TRUE
);
6375 if (rc
!= ERROR_SUCCESS
)
6378 rc
= MSIREG_OpenUserFeaturesKey(productcode
,&hukey
,TRUE
);
6379 if (rc
!= ERROR_SUCCESS
)
6382 /* here the guids are base 85 encoded */
6383 for (i
= 0; i
< package
->loaded_features
; i
++)
6389 BOOL absent
= FALSE
;
6391 if (!ACTION_VerifyFeatureForAction(package
,i
,INSTALLSTATE_LOCAL
) &&
6392 !ACTION_VerifyFeatureForAction(package
,i
,INSTALLSTATE_SOURCE
) &&
6393 !ACTION_VerifyFeatureForAction(package
,i
,INSTALLSTATE_ADVERTISED
))
6396 size
= package
->features
[i
].ComponentCount
*21;
6398 if (package
->features
[i
].Feature_Parent
[0])
6399 size
+= strlenW(package
->features
[i
].Feature_Parent
)+2;
6401 data
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
6404 for (j
= 0; j
< package
->features
[i
].ComponentCount
; j
++)
6407 memset(buf
,0,sizeof(buf
));
6408 if (package
->components
6409 [package
->features
[i
].Components
[j
]].ComponentId
[0]!=0)
6411 TRACE("From %s\n",debugstr_w(package
->components
6412 [package
->features
[i
].Components
[j
]].ComponentId
));
6413 CLSIDFromString(package
->components
6414 [package
->features
[i
].Components
[j
]].ComponentId
,
6416 encode_base85_guid(&clsid
,buf
);
6417 TRACE("to %s\n",debugstr_w(buf
));
6421 if (package
->features
[i
].Feature_Parent
[0])
6423 static const WCHAR sep
[] = {'\2',0};
6425 strcatW(data
,package
->features
[i
].Feature_Parent
);
6428 size
= (strlenW(data
)+1)*sizeof(WCHAR
);
6429 RegSetValueExW(hkey
,package
->features
[i
].Feature
,0,REG_SZ
,
6431 HeapFree(GetProcessHeap(),0,data
);
6435 size
= strlenW(package
->features
[i
].Feature_Parent
)*sizeof(WCHAR
);
6436 RegSetValueExW(hukey
,package
->features
[i
].Feature
,0,REG_SZ
,
6437 (LPSTR
)package
->features
[i
].Feature_Parent
,size
);
6441 size
= (strlenW(package
->features
[i
].Feature_Parent
)+2)*
6443 data
= HeapAlloc(GetProcessHeap(),0,size
);
6445 strcpyW(&data
[1],package
->features
[i
].Feature_Parent
);
6446 RegSetValueExW(hukey
,package
->features
[i
].Feature
,0,REG_SZ
,
6448 HeapFree(GetProcessHeap(),0,data
);
6455 HeapFree(GetProcessHeap(), 0, productcode
);
6459 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
6466 static WCHAR szNONE
[] = {0};
6467 static const WCHAR szWindowsInstaler
[] =
6468 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
6469 static const WCHAR szPropKeys
[][80] =
6471 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0},
6472 {'A','R','P','C','O','N','T','A','C','T',0},
6473 {'A','R','P','C','O','M','M','E','N','T','S',0},
6474 {'P','r','o','d','u','c','t','N','a','m','e',0},
6475 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0},
6476 {'A','R','P','H','E','L','P','L','I','N','K',0},
6477 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0},
6478 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0},
6479 {'S','o','u','r','c','e','D','i','r',0},
6480 {'M','a','n','u','f','a','c','t','u','r','e','r',0},
6481 {'A','R','P','R','E','A','D','M','E',0},
6482 {'A','R','P','S','I','Z','E',0},
6483 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0},
6484 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0},
6488 static const WCHAR szRegKeys
[][80] =
6490 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0},
6491 {'C','o','n','t','a','c','t',0},
6492 {'C','o','m','m','e','n','t','s',0},
6493 {'D','i','s','p','l','a','y','N','a','m','e',0},
6494 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0},
6495 {'H','e','l','p','L','i','n','k',0},
6496 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0},
6497 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0},
6498 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0},
6499 {'P','u','b','l','i','s','h','e','r',0},
6500 {'R','e','a','d','m','e',0},
6501 {'S','i','z','e',0},
6502 {'U','R','L','I','n','f','o','A','b','o','u','t',0},
6503 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0},
6507 static const WCHAR installerPathFmt
[] = {
6509 'I','n','s','t','a','l','l','e','r','\\',0};
6510 static const WCHAR fmt
[] = {
6512 'I','n','s','t','a','l','l','e','r','\\',
6513 '%','x','.','m','s','i',0};
6514 static const WCHAR szLocalPackage
[]=
6515 {'L','o','c','a','l','P','a','c','k','a','g','e',0};
6516 static const WCHAR szUpgradeCode
[] =
6517 {'U','p','g','r','a','d','e','C','o','d','e',0};
6518 LPWSTR upgrade_code
;
6519 WCHAR windir
[MAX_PATH
], path
[MAX_PATH
], packagefile
[MAX_PATH
];
6523 return ERROR_INVALID_HANDLE
;
6525 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
6529 rc
= MSIREG_OpenUninstallKey(productcode
,&hkey
,TRUE
);
6530 if (rc
!= ERROR_SUCCESS
)
6533 /* dump all the info i can grab */
6534 FIXME("Flesh out more information \n");
6537 while (szPropKeys
[i
][0]!=0)
6539 buffer
= load_dynamic_property(package
,szPropKeys
[i
],&rc
);
6540 if (rc
!= ERROR_SUCCESS
)
6542 size
= strlenW(buffer
)*sizeof(WCHAR
);
6543 RegSetValueExW(hkey
,szRegKeys
[i
],0,REG_SZ
,(LPSTR
)buffer
,size
);
6549 RegSetValueExW(hkey
,szWindowsInstaler
,0,REG_DWORD
,(LPSTR
)&rc
,size
);
6551 /* copy the package locally */
6552 num
= GetTickCount() & 0xffff;
6556 GetWindowsDirectoryW(windir
, sizeof(windir
) / sizeof(windir
[0]));
6557 snprintfW(packagefile
,sizeof(packagefile
)/sizeof(packagefile
[0]),fmt
,
6561 HANDLE handle
= CreateFileW(packagefile
,GENERIC_WRITE
, 0, NULL
,
6562 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
6563 if (handle
!= INVALID_HANDLE_VALUE
)
6565 CloseHandle(handle
);
6568 if (GetLastError() != ERROR_FILE_EXISTS
&&
6569 GetLastError() != ERROR_SHARING_VIOLATION
)
6571 if (!(++num
& 0xffff)) num
= 1;
6572 sprintfW(packagefile
,fmt
,num
);
6573 } while (num
!= start
);
6575 snprintfW(path
,sizeof(path
)/sizeof(path
[0]),installerPathFmt
,windir
);
6576 create_full_pathW(path
);
6577 TRACE("Copying to local package %s\n",debugstr_w(packagefile
));
6578 if (!CopyFileW(package
->PackagePath
,packagefile
,FALSE
))
6579 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
6580 debugstr_w(package
->PackagePath
), debugstr_w(packagefile
),
6582 size
= strlenW(packagefile
)*sizeof(WCHAR
);
6583 RegSetValueExW(hkey
,szLocalPackage
,0,REG_SZ
,(LPSTR
)packagefile
,size
);
6585 /* Handle Upgrade Codes */
6586 upgrade_code
= load_dynamic_property(package
,szUpgradeCode
, NULL
);
6591 MSIREG_OpenUpgradeCodesKey(upgrade_code
, &hkey2
, TRUE
);
6592 squash_guid(productcode
,squashed
);
6593 RegSetValueExW(hkey2
, squashed
, 0,REG_SZ
,NULL
,0);
6595 MSIREG_OpenUserUpgradeCodesKey(upgrade_code
, &hkey2
, TRUE
);
6596 squash_guid(productcode
,squashed
);
6597 RegSetValueExW(hkey2
, squashed
, 0,REG_SZ
,NULL
,0);
6600 HeapFree(GetProcessHeap(),0,upgrade_code
);
6604 HeapFree(GetProcessHeap(),0,productcode
);
6607 return ERROR_SUCCESS
;
6610 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
6615 return ERROR_INVALID_HANDLE
;
6617 rc
= execute_script(package
,INSTALL_SCRIPT
);
6622 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
6627 return ERROR_INVALID_HANDLE
;
6629 /* turn off scheduleing */
6630 package
->script
->CurrentlyScripting
= FALSE
;
6632 /* first do the same as an InstallExecute */
6633 rc
= ACTION_InstallExecute(package
);
6634 if (rc
!= ERROR_SUCCESS
)
6637 /* then handle Commit Actions */
6638 rc
= execute_script(package
,COMMIT_SCRIPT
);
6643 static UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
6645 static const WCHAR RunOnce
[] = {
6646 'S','o','f','t','w','a','r','e','\\',
6647 'M','i','c','r','o','s','o','f','t','\\',
6648 'W','i','n','d','o','w','s','\\',
6649 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
6650 'R','u','n','O','n','c','e',0};
6651 static const WCHAR InstallRunOnce
[] = {
6652 'S','o','f','t','w','a','r','e','\\',
6653 'M','i','c','r','o','s','o','f','t','\\',
6654 'W','i','n','d','o','w','s','\\',
6655 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
6656 'I','n','s','t','a','l','l','e','r','\\',
6657 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
6659 static const WCHAR msiexec_fmt
[] = {
6661 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
6662 '\"','%','s','\"',0};
6663 static const WCHAR install_fmt
[] = {
6664 '/','I',' ','\"','%','s','\"',' ',
6665 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
6666 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
6667 WCHAR buffer
[256], sysdir
[MAX_PATH
];
6670 WCHAR squished_pc
[100];
6673 static const WCHAR szLUS
[] = {
6674 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0};
6675 static const WCHAR szSourceList
[] = {
6676 'S','o','u','r','c','e','L','i','s','t',0};
6677 static const WCHAR szPackageName
[] = {
6678 'P','a','c','k','a','g','e','N','a','m','e',0};
6681 return ERROR_INVALID_HANDLE
;
6683 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
6687 squash_guid(productcode
,squished_pc
);
6689 GetSystemDirectoryW(sysdir
, sizeof(sysdir
)/sizeof(sysdir
[0]));
6690 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
6691 snprintfW(buffer
,sizeof(buffer
)/sizeof(buffer
[0]),msiexec_fmt
,sysdir
,
6694 size
= strlenW(buffer
)*sizeof(WCHAR
);
6695 RegSetValueExW(hkey
,squished_pc
,0,REG_SZ
,(LPSTR
)buffer
,size
);
6698 TRACE("Reboot command %s\n",debugstr_w(buffer
));
6700 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
6701 sprintfW(buffer
,install_fmt
,productcode
,squished_pc
);
6703 size
= strlenW(buffer
)*sizeof(WCHAR
);
6704 RegSetValueExW(hkey
,squished_pc
,0,REG_SZ
,(LPSTR
)buffer
,size
);
6707 rc
= MSIREG_OpenUserProductsKey(productcode
,&hukey
,TRUE
);
6708 if (rc
== ERROR_SUCCESS
)
6712 RegCreateKeyW(hukey
, szSourceList
, &hukey2
);
6713 buf
= load_dynamic_property(package
,cszSourceDir
,NULL
);
6714 size
= strlenW(buf
)*sizeof(WCHAR
);
6715 RegSetValueExW(hukey2
,szLUS
,0,REG_SZ
,(LPSTR
)buf
,size
);
6716 HeapFree(GetProcessHeap(),0,buf
);
6718 buf
= strrchrW(package
->PackagePath
,'\\');
6722 size
= strlenW(buf
)*sizeof(WCHAR
);
6723 RegSetValueExW(hukey2
,szPackageName
,0,REG_SZ
,(LPSTR
)buf
,size
);
6726 RegCloseKey(hukey2
);
6728 HeapFree(GetProcessHeap(),0,productcode
);
6730 return ERROR_INSTALL_SUSPEND
;
6733 UINT
ACTION_ResolveSource(MSIPACKAGE
* package
)
6736 * we are currently doing what should be done here in the top level Install
6737 * however for Adminastrative and uninstalls this step will be needed
6739 return ERROR_SUCCESS
;
6742 static LPWSTR
create_component_advertise_string(MSIPACKAGE
* package
,
6743 MSICOMPONENT
* component
, LPCWSTR feature
)
6745 LPWSTR productid
=NULL
;
6747 WCHAR productid_85
[21];
6748 WCHAR component_85
[21];
6750 * I have a fair bit of confusion as to when a < is used and when a > is
6751 * used. I do not think i have it right...
6753 * Ok it appears that the > is used if there is a guid for the compoenent
6754 * and the < is used if not.
6756 static WCHAR fmt1
[] = {'%','s','%','s','<',0,0};
6757 static WCHAR fmt2
[] = {'%','s','%','s','>','%','s',0,0};
6758 LPWSTR output
= NULL
;
6761 memset(productid_85
,0,sizeof(productid_85
));
6762 memset(component_85
,0,sizeof(component_85
));
6764 productid
= load_dynamic_property(package
,szProductCode
,NULL
);
6765 CLSIDFromString(productid
, &clsid
);
6767 encode_base85_guid(&clsid
,productid_85
);
6769 CLSIDFromString(component
->ComponentId
, &clsid
);
6770 encode_base85_guid(&clsid
,component_85
);
6772 TRACE("Doing something with this... %s %s %s\n",
6773 debugstr_w(productid_85
), debugstr_w(feature
),
6774 debugstr_w(component_85
));
6776 sz
= lstrlenW(productid_85
) + lstrlenW(feature
);
6778 sz
+= lstrlenW(component_85
);
6781 sz
*= sizeof(WCHAR
);
6783 output
= HeapAlloc(GetProcessHeap(),0,sz
);
6784 memset(output
,0,sz
);
6787 sprintfW(output
,fmt2
,productid_85
,feature
,component_85
);
6789 sprintfW(output
,fmt1
,productid_85
,feature
);
6791 HeapFree(GetProcessHeap(),0,productid
);
6796 static UINT
register_verb(MSIPACKAGE
*package
, LPCWSTR progid
,
6797 MSICOMPONENT
* component
, MSIEXTENSION
* extension
,
6798 MSIVERB
* verb
, INT
* Sequence
)
6802 static const WCHAR szShell
[] = {'s','h','e','l','l',0};
6803 static const WCHAR szCommand
[] = {'c','o','m','m','a','n','d',0};
6804 static const WCHAR fmt
[] = {'\"','%','s','\"',' ','%','s',0};
6805 static const WCHAR fmt2
[] = {'\"','%','s','\"',0};
6810 keyname
= build_directory_name(4, progid
, szShell
, verb
->Verb
, szCommand
);
6812 TRACE("Making Key %s\n",debugstr_w(keyname
));
6813 RegCreateKeyW(HKEY_CLASSES_ROOT
, keyname
, &key
);
6814 size
= strlenW(component
->FullKeypath
);
6816 size
+= strlenW(verb
->Argument
);
6819 command
= HeapAlloc(GetProcessHeap(),0, size
* sizeof (WCHAR
));
6821 sprintfW(command
, fmt
, component
->FullKeypath
, verb
->Argument
);
6823 sprintfW(command
, fmt2
, component
->FullKeypath
);
6825 RegSetValueExW(key
,NULL
,0,REG_SZ
, (LPVOID
)command
, (strlenW(command
)+1)*
6827 HeapFree(GetProcessHeap(),0,command
);
6829 advertise
= create_component_advertise_string(package
, component
,
6830 package
->features
[extension
->FeatureIndex
].Feature
);
6832 size
= strlenW(advertise
);
6835 size
+= strlenW(verb
->Argument
);
6838 command
= HeapAlloc(GetProcessHeap(),0, size
* sizeof (WCHAR
));
6839 memset(command
,0,size
*sizeof(WCHAR
));
6841 strcpyW(command
,advertise
);
6844 static const WCHAR szSpace
[] = {' ',0};
6845 strcatW(command
,szSpace
);
6846 strcatW(command
,verb
->Argument
);
6849 RegSetValueExW(key
, szCommand
, 0, REG_MULTI_SZ
, (LPBYTE
)command
,
6850 (strlenW(command
)+2)*sizeof(WCHAR
));
6853 HeapFree(GetProcessHeap(),0,keyname
);
6854 HeapFree(GetProcessHeap(),0,advertise
);
6855 HeapFree(GetProcessHeap(),0,command
);
6859 keyname
= build_directory_name(3, progid
, szShell
, verb
->Verb
);
6860 RegCreateKeyW(HKEY_CLASSES_ROOT
, keyname
, &key
);
6861 RegSetValueExW(key
,NULL
,0,REG_SZ
, (LPVOID
)verb
->Command
,
6862 (strlenW(verb
->Command
)+1) *sizeof(WCHAR
));
6864 HeapFree(GetProcessHeap(),0,keyname
);
6867 if (verb
->Sequence
!= MSI_NULL_INTEGER
)
6869 if (*Sequence
== MSI_NULL_INTEGER
|| verb
->Sequence
< *Sequence
)
6871 *Sequence
= verb
->Sequence
;
6872 keyname
= build_directory_name(2, progid
, szShell
);
6873 RegCreateKeyW(HKEY_CLASSES_ROOT
, keyname
, &key
);
6874 RegSetValueExW(key
,NULL
,0,REG_SZ
, (LPVOID
)verb
->Verb
,
6875 (strlenW(verb
->Verb
)+1) *sizeof(WCHAR
));
6877 HeapFree(GetProcessHeap(),0,keyname
);
6880 return ERROR_SUCCESS
;
6883 static UINT
ACTION_RegisterExtensionInfo(MSIPACKAGE
*package
)
6885 static const WCHAR szContentType
[] =
6886 {'C','o','n','t','e','n','t',' ','T','y','p','e',0 };
6890 BOOL install_on_demand
= TRUE
;
6893 return ERROR_INVALID_HANDLE
;
6895 load_classes_and_such(package
);
6897 /* We need to set install_on_demand based on if the shell handles advertised
6898 * shortcuts and the like. Because Mike McCormack is working on this i am
6899 * going to default to TRUE
6902 for (i
= 0; i
< package
->loaded_extensions
; i
++)
6904 WCHAR extension
[257];
6907 index
= package
->extensions
[i
].ComponentIndex
;
6908 f_index
= package
->extensions
[i
].FeatureIndex
;
6914 * yes. MSDN says that these are based on _Feature_ not on
6915 * Component. So verify the feature is to be installed
6917 if ((!ACTION_VerifyFeatureForAction(package
, f_index
,
6918 INSTALLSTATE_LOCAL
)) &&
6919 !(install_on_demand
&& ACTION_VerifyFeatureForAction(package
,
6920 f_index
, INSTALLSTATE_ADVERTISED
)))
6922 TRACE("Skipping extension %s reg due to disabled feature %s\n",
6923 debugstr_w(package
->extensions
[i
].Extension
),
6924 debugstr_w(package
->features
[f_index
].Feature
));
6929 TRACE("Registering extension %s index %i\n",
6930 debugstr_w(package
->extensions
[i
].Extension
), i
);
6932 package
->extensions
[i
].Installed
= TRUE
;
6934 /* this is only registered if the extension has at least 1 verb
6937 if (package
->extensions
[i
].ProgIDIndex
>= 0 &&
6938 package
->extensions
[i
].VerbCount
> 0)
6939 mark_progid_for_install(package
, package
->extensions
[i
].ProgIDIndex
);
6941 if (package
->extensions
[i
].MIMEIndex
>= 0)
6942 mark_mime_for_install(package
, package
->extensions
[i
].MIMEIndex
);
6946 strcatW(extension
,package
->extensions
[i
].Extension
);
6948 RegCreateKeyW(HKEY_CLASSES_ROOT
,extension
,&hkey
);
6950 if (package
->extensions
[i
].MIMEIndex
>= 0)
6952 RegSetValueExW(hkey
,szContentType
,0,REG_SZ
,
6953 (LPVOID
)package
->mimes
[package
->extensions
[i
].
6954 MIMEIndex
].ContentType
,
6955 (strlenW(package
->mimes
[package
->extensions
[i
].
6956 MIMEIndex
].ContentType
)+1)*sizeof(WCHAR
));
6959 if (package
->extensions
[i
].ProgIDIndex
>= 0 ||
6960 package
->extensions
[i
].ProgIDText
)
6962 static const WCHAR szSN
[] =
6963 {'\\','S','h','e','l','l','N','e','w',0};
6968 INT Sequence
= MSI_NULL_INTEGER
;
6970 if (package
->extensions
[i
].ProgIDIndex
>= 0)
6971 progid
= package
->progids
[package
->extensions
[i
].
6972 ProgIDIndex
].ProgID
;
6974 progid
= package
->extensions
[i
].ProgIDText
;
6976 RegSetValueExW(hkey
,NULL
,0,REG_SZ
,(LPVOID
)progid
,
6977 (strlenW(progid
)+1)*sizeof(WCHAR
));
6979 newkey
= HeapAlloc(GetProcessHeap(),0,
6980 (strlenW(progid
)+strlenW(szSN
)+1) * sizeof(WCHAR
));
6982 strcpyW(newkey
,progid
);
6983 strcatW(newkey
,szSN
);
6984 RegCreateKeyW(hkey
,newkey
,&hkey2
);
6987 HeapFree(GetProcessHeap(),0,newkey
);
6989 /* do all the verbs */
6990 for (v
= 0; v
< package
->extensions
[i
].VerbCount
; v
++)
6991 register_verb(package
, progid
,
6992 &package
->components
[index
],
6993 &package
->extensions
[i
],
6994 &package
->verbs
[package
->extensions
[i
].Verbs
[v
]],
7000 uirow
= MSI_CreateRecord(1);
7001 MSI_RecordSetStringW(uirow
,1,package
->extensions
[i
].Extension
);
7002 ui_actiondata(package
,szRegisterExtensionInfo
,uirow
);
7003 msiobj_release(&uirow
->hdr
);
7006 return ERROR_SUCCESS
;
7009 static UINT
ACTION_RegisterMIMEInfo(MSIPACKAGE
*package
)
7011 static const WCHAR szExten
[] =
7012 {'E','x','t','e','n','s','i','o','n',0 };
7018 return ERROR_INVALID_HANDLE
;
7020 load_classes_and_such(package
);
7022 for (i
= 0; i
< package
->loaded_mimes
; i
++)
7024 WCHAR extension
[257];
7027 static const WCHAR fmt
[] =
7028 {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
7029 'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0};
7033 * check if the MIME is to be installed. Either as requesed by an
7034 * extension or Class
7036 package
->mimes
[i
].InstallMe
= ((package
->mimes
[i
].InstallMe
) ||
7037 (package
->mimes
[i
].ClassIndex
>= 0 &&
7038 package
->classes
[package
->mimes
[i
].ClassIndex
].Installed
) ||
7039 (package
->mimes
[i
].ExtensionIndex
>=0 &&
7040 package
->extensions
[package
->mimes
[i
].ExtensionIndex
].Installed
));
7042 if (!package
->mimes
[i
].InstallMe
)
7044 TRACE("MIME %s not scheduled to be installed\n",
7045 debugstr_w(package
->mimes
[i
].ContentType
));
7049 mime
= package
->mimes
[i
].ContentType
;
7050 exten
= package
->extensions
[package
->mimes
[i
].ExtensionIndex
].Extension
;
7053 strcatW(extension
,exten
);
7055 key
= HeapAlloc(GetProcessHeap(),0,(strlenW(mime
)+strlenW(fmt
)+1) *
7057 sprintfW(key
,fmt
,mime
);
7058 RegCreateKeyW(HKEY_CLASSES_ROOT
,key
,&hkey
);
7059 RegSetValueExW(hkey
,szExten
,0,REG_SZ
,(LPVOID
)extension
,
7060 (strlenW(extension
)+1)*sizeof(WCHAR
));
7062 HeapFree(GetProcessHeap(),0,key
);
7064 if (package
->mimes
[i
].CLSID
[0])
7066 FIXME("Handle non null for field 3\n");
7071 uirow
= MSI_CreateRecord(2);
7072 MSI_RecordSetStringW(uirow
,1,package
->mimes
[i
].ContentType
);
7073 MSI_RecordSetStringW(uirow
,2,exten
);
7074 ui_actiondata(package
,szRegisterMIMEInfo
,uirow
);
7075 msiobj_release(&uirow
->hdr
);
7078 return ERROR_SUCCESS
;
7081 static UINT
ACTION_RegisterUser(MSIPACKAGE
*package
)
7083 static const WCHAR szProductID
[]=
7084 {'P','r','o','d','u','c','t','I','D',0};
7092 static const WCHAR szPropKeys
[][80] =
7094 {'P','r','o','d','u','c','t','I','D',0},
7095 {'U','S','E','R','N','A','M','E',0},
7096 {'C','O','M','P','A','N','Y','N','A','M','E',0},
7100 static const WCHAR szRegKeys
[][80] =
7102 {'P','r','o','d','u','c','t','I','D',0},
7103 {'R','e','g','O','w','n','e','r',0},
7104 {'R','e','g','C','o','m','p','a','n','y',0},
7109 return ERROR_INVALID_HANDLE
;
7111 productid
= load_dynamic_property(package
,szProductID
,&rc
);
7113 return ERROR_SUCCESS
;
7115 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
7119 rc
= MSIREG_OpenUninstallKey(productcode
,&hkey
,TRUE
);
7120 if (rc
!= ERROR_SUCCESS
)
7124 while (szPropKeys
[i
][0]!=0)
7126 buffer
= load_dynamic_property(package
,szPropKeys
[i
],&rc
);
7127 if (rc
== ERROR_SUCCESS
)
7129 size
= strlenW(buffer
)*sizeof(WCHAR
);
7130 RegSetValueExW(hkey
,szRegKeys
[i
],0,REG_SZ
,(LPSTR
)buffer
,size
);
7133 RegSetValueExW(hkey
,szRegKeys
[i
],0,REG_SZ
,NULL
,0);
7138 HeapFree(GetProcessHeap(),0,productcode
);
7139 HeapFree(GetProcessHeap(),0,productid
);
7142 return ERROR_SUCCESS
;
7146 static UINT
ACTION_ExecuteAction(MSIPACKAGE
*package
)
7149 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
7155 * Code based off of code located here
7156 * http://www.codeproject.com/gdi/fontnamefromfile.asp
7158 * Using string index 4 (full font name) instead of 1 (family name)
7160 static LPWSTR
load_ttfname_from(LPCWSTR filename
)
7166 typedef struct _tagTT_OFFSET_TABLE
{
7167 USHORT uMajorVersion
;
7168 USHORT uMinorVersion
;
7169 USHORT uNumOfTables
;
7170 USHORT uSearchRange
;
7171 USHORT uEntrySelector
;
7175 typedef struct _tagTT_TABLE_DIRECTORY
{
7176 char szTag
[4]; /* table name */
7177 ULONG uCheckSum
; /* Check sum */
7178 ULONG uOffset
; /* Offset from beginning of file */
7179 ULONG uLength
; /* length of the table in bytes */
7180 }TT_TABLE_DIRECTORY
;
7182 typedef struct _tagTT_NAME_TABLE_HEADER
{
7183 USHORT uFSelector
; /* format selector. Always 0 */
7184 USHORT uNRCount
; /* Name Records count */
7185 USHORT uStorageOffset
; /* Offset for strings storage,
7186 * from start of the table */
7187 }TT_NAME_TABLE_HEADER
;
7189 typedef struct _tagTT_NAME_RECORD
{
7194 USHORT uStringLength
;
7195 USHORT uStringOffset
; /* from start of storage area */
7198 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
7199 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
7201 handle
= CreateFileW(filename
,GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
7202 FILE_ATTRIBUTE_NORMAL
, 0 );
7203 if (handle
!= INVALID_HANDLE_VALUE
)
7205 TT_TABLE_DIRECTORY tblDir
;
7206 BOOL bFound
= FALSE
;
7207 TT_OFFSET_TABLE ttOffsetTable
;
7209 ReadFile(handle
,&ttOffsetTable
, sizeof(TT_OFFSET_TABLE
),NULL
,NULL
);
7210 ttOffsetTable
.uNumOfTables
= SWAPWORD(ttOffsetTable
.uNumOfTables
);
7211 ttOffsetTable
.uMajorVersion
= SWAPWORD(ttOffsetTable
.uMajorVersion
);
7212 ttOffsetTable
.uMinorVersion
= SWAPWORD(ttOffsetTable
.uMinorVersion
);
7214 if (ttOffsetTable
.uMajorVersion
!= 1 ||
7215 ttOffsetTable
.uMinorVersion
!= 0)
7218 for (i
=0; i
< ttOffsetTable
.uNumOfTables
; i
++)
7220 ReadFile(handle
,&tblDir
, sizeof(TT_TABLE_DIRECTORY
),NULL
,NULL
);
7221 if (strncmp(tblDir
.szTag
,"name",4)==0)
7224 tblDir
.uLength
= SWAPLONG(tblDir
.uLength
);
7225 tblDir
.uOffset
= SWAPLONG(tblDir
.uOffset
);
7232 TT_NAME_TABLE_HEADER ttNTHeader
;
7233 TT_NAME_RECORD ttRecord
;
7235 SetFilePointer(handle
, tblDir
.uOffset
, NULL
, FILE_BEGIN
);
7236 ReadFile(handle
,&ttNTHeader
, sizeof(TT_NAME_TABLE_HEADER
),
7239 ttNTHeader
.uNRCount
= SWAPWORD(ttNTHeader
.uNRCount
);
7240 ttNTHeader
.uStorageOffset
= SWAPWORD(ttNTHeader
.uStorageOffset
);
7242 for(i
=0; i
<ttNTHeader
.uNRCount
; i
++)
7244 ReadFile(handle
,&ttRecord
, sizeof(TT_NAME_RECORD
),NULL
,NULL
);
7245 ttRecord
.uNameID
= SWAPWORD(ttRecord
.uNameID
);
7246 /* 4 is the Full Font Name */
7247 if(ttRecord
.uNameID
== 4)
7251 static LPCSTR tt
= " (TrueType)";
7253 ttRecord
.uStringLength
= SWAPWORD(ttRecord
.uStringLength
);
7254 ttRecord
.uStringOffset
= SWAPWORD(ttRecord
.uStringOffset
);
7255 nPos
= SetFilePointer(handle
, 0, NULL
, FILE_CURRENT
);
7256 SetFilePointer(handle
, tblDir
.uOffset
+
7257 ttRecord
.uStringOffset
+
7258 ttNTHeader
.uStorageOffset
,
7260 buf
= HeapAlloc(GetProcessHeap(), 0,
7261 ttRecord
.uStringLength
+ 1 + strlen(tt
));
7262 memset(buf
, 0, ttRecord
.uStringLength
+ 1 + strlen(tt
));
7263 ReadFile(handle
, buf
, ttRecord
.uStringLength
, NULL
, NULL
);
7264 if (strlen(buf
) > 0)
7267 ret
= strdupAtoW(buf
);
7268 HeapFree(GetProcessHeap(),0,buf
);
7272 HeapFree(GetProcessHeap(),0,buf
);
7273 SetFilePointer(handle
,nPos
, NULL
, FILE_BEGIN
);
7277 CloseHandle(handle
);
7280 ERR("Unable to open font file %s\n", debugstr_w(filename
));
7282 TRACE("Returning fontname %s\n",debugstr_w(ret
));
7286 static UINT
ACTION_RegisterFonts(MSIPACKAGE
*package
)
7290 MSIRECORD
* row
= 0;
7291 static const WCHAR ExecSeqQuery
[] =
7292 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7293 '`','F','o','n','t','`',0};
7294 static const WCHAR regfont1
[] =
7295 {'S','o','f','t','w','a','r','e','\\',
7296 'M','i','c','r','o','s','o','f','t','\\',
7297 'W','i','n','d','o','w','s',' ','N','T','\\',
7298 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
7299 'F','o','n','t','s',0};
7300 static const WCHAR regfont2
[] =
7301 {'S','o','f','t','w','a','r','e','\\',
7302 'M','i','c','r','o','s','o','f','t','\\',
7303 'W','i','n','d','o','w','s','\\',
7304 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
7305 'F','o','n','t','s',0};
7309 TRACE("%p\n", package
);
7311 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
7312 if (rc
!= ERROR_SUCCESS
)
7314 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc
);
7315 return ERROR_SUCCESS
;
7318 rc
= MSI_ViewExecute(view
, 0);
7319 if (rc
!= ERROR_SUCCESS
)
7321 MSI_ViewClose(view
);
7322 msiobj_release(&view
->hdr
);
7323 TRACE("MSI_ViewExecute returned %d\n", rc
);
7324 return ERROR_SUCCESS
;
7327 RegCreateKeyW(HKEY_LOCAL_MACHINE
,regfont1
,&hkey1
);
7328 RegCreateKeyW(HKEY_LOCAL_MACHINE
,regfont2
,&hkey2
);
7337 rc
= MSI_ViewFetch(view
,&row
);
7338 if (rc
!= ERROR_SUCCESS
)
7344 file
= load_dynamic_stringW(row
,1);
7345 index
= get_loaded_file(package
,file
);
7348 ERR("Unable to load file\n");
7349 HeapFree(GetProcessHeap(),0,file
);
7353 /* check to make sure that component is installed */
7354 if (!ACTION_VerifyComponentForAction(package
,
7355 package
->files
[index
].ComponentIndex
, INSTALLSTATE_LOCAL
))
7357 TRACE("Skipping: Component not scheduled for install\n");
7358 HeapFree(GetProcessHeap(),0,file
);
7360 msiobj_release(&row
->hdr
);
7365 if (MSI_RecordIsNull(row
,2))
7366 name
= load_ttfname_from(package
->files
[index
].TargetPath
);
7368 name
= load_dynamic_stringW(row
,2);
7372 size
= strlenW(package
->files
[index
].FileName
) * sizeof(WCHAR
);
7373 RegSetValueExW(hkey1
,name
,0,REG_SZ
,
7374 (LPBYTE
)package
->files
[index
].FileName
,size
);
7375 RegSetValueExW(hkey2
,name
,0,REG_SZ
,
7376 (LPBYTE
)package
->files
[index
].FileName
,size
);
7379 HeapFree(GetProcessHeap(),0,file
);
7380 HeapFree(GetProcessHeap(),0,name
);
7381 msiobj_release(&row
->hdr
);
7383 MSI_ViewClose(view
);
7384 msiobj_release(&view
->hdr
);
7389 TRACE("returning %d\n", rc
);
7393 static UINT
ITERATE_PublishComponent(MSIRECORD
*rec
, LPVOID param
)
7395 MSIPACKAGE
*package
= (MSIPACKAGE
*)param
;
7396 LPWSTR compgroupid
=NULL
;
7397 LPWSTR feature
=NULL
;
7399 LPWSTR qualifier
= NULL
;
7400 LPWSTR component
= NULL
;
7401 LPWSTR advertise
= NULL
;
7402 LPWSTR output
= NULL
;
7404 UINT rc
= ERROR_SUCCESS
;
7408 component
= load_dynamic_stringW(rec
,3);
7409 index
= get_loaded_component(package
,component
);
7411 if (!ACTION_VerifyComponentForAction(package
, index
,
7412 INSTALLSTATE_LOCAL
) &&
7413 !ACTION_VerifyComponentForAction(package
, index
,
7414 INSTALLSTATE_SOURCE
) &&
7415 !ACTION_VerifyComponentForAction(package
, index
,
7416 INSTALLSTATE_ADVERTISED
))
7418 TRACE("Skipping: Component %s not scheduled for install\n",
7419 debugstr_w(component
));
7421 HeapFree(GetProcessHeap(),0,component
);
7422 return ERROR_SUCCESS
;
7425 compgroupid
= load_dynamic_stringW(rec
,1);
7427 rc
= MSIREG_OpenUserComponentsKey(compgroupid
, &hkey
, TRUE
);
7428 if (rc
!= ERROR_SUCCESS
)
7431 text
= load_dynamic_stringW(rec
,4);
7432 qualifier
= load_dynamic_stringW(rec
,2);
7433 feature
= load_dynamic_stringW(rec
,5);
7435 advertise
= create_component_advertise_string(package
,
7436 &package
->components
[index
], feature
);
7438 sz
= strlenW(advertise
);
7441 sz
+= lstrlenW(text
);
7444 sz
*= sizeof(WCHAR
);
7446 output
= HeapAlloc(GetProcessHeap(),0,sz
);
7447 memset(output
,0,sz
);
7448 strcpyW(output
,advertise
);
7451 strcatW(output
,text
);
7453 sz
= (lstrlenW(output
)+2) * sizeof(WCHAR
);
7454 RegSetValueExW(hkey
, qualifier
,0,REG_MULTI_SZ
, (LPBYTE
)output
, sz
);
7458 HeapFree(GetProcessHeap(),0,output
);
7459 HeapFree(GetProcessHeap(),0,compgroupid
);
7460 HeapFree(GetProcessHeap(),0,component
);
7461 HeapFree(GetProcessHeap(),0,feature
);
7462 HeapFree(GetProcessHeap(),0,text
);
7463 HeapFree(GetProcessHeap(),0,qualifier
);
7469 * At present I am ignorning the advertised components part of this and only
7470 * focusing on the qualified component sets
7472 static UINT
ACTION_PublishComponents(MSIPACKAGE
*package
)
7476 static const WCHAR ExecSeqQuery
[] =
7477 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7478 '`','P','u','b','l','i','s','h',
7479 'C','o','m','p','o','n','e','n','t','`',0};
7481 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
7482 if (rc
!= ERROR_SUCCESS
)
7483 return ERROR_SUCCESS
;
7485 rc
= MSI_IterateRecords(view
, NULL
, ITERATE_PublishComponent
, package
);
7486 msiobj_release(&view
->hdr
);
7491 /* Msi functions that seem appropriate here */
7493 /***********************************************************************
7494 * MsiDoActionA (MSI.@)
7496 UINT WINAPI
MsiDoActionA( MSIHANDLE hInstall
, LPCSTR szAction
)
7501 TRACE(" exteral attempt at action %s\n",szAction
);
7504 return ERROR_FUNCTION_FAILED
;
7506 return ERROR_FUNCTION_FAILED
;
7508 szwAction
= strdupAtoW(szAction
);
7511 return ERROR_FUNCTION_FAILED
;
7514 rc
= MsiDoActionW(hInstall
, szwAction
);
7515 HeapFree(GetProcessHeap(),0,szwAction
);
7519 /***********************************************************************
7520 * MsiDoActionW (MSI.@)
7522 UINT WINAPI
MsiDoActionW( MSIHANDLE hInstall
, LPCWSTR szAction
)
7524 MSIPACKAGE
*package
;
7525 UINT ret
= ERROR_INVALID_HANDLE
;
7527 TRACE(" external attempt at action %s \n",debugstr_w(szAction
));
7529 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
7532 ret
= ACTION_PerformUIAction(package
,szAction
);
7533 msiobj_release( &package
->hdr
);
7538 UINT WINAPI
MsiGetTargetPathA( MSIHANDLE hInstall
, LPCSTR szFolder
,
7539 LPSTR szPathBuf
, DWORD
* pcchPathBuf
)
7545 TRACE("getting folder %s %p %li\n",szFolder
,szPathBuf
, *pcchPathBuf
);
7548 return ERROR_FUNCTION_FAILED
;
7550 return ERROR_FUNCTION_FAILED
;
7552 szwFolder
= strdupAtoW(szFolder
);
7555 return ERROR_FUNCTION_FAILED
;
7557 szwPathBuf
= HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf
* sizeof(WCHAR
));
7559 rc
= MsiGetTargetPathW(hInstall
, szwFolder
, szwPathBuf
,pcchPathBuf
);
7561 WideCharToMultiByte( CP_ACP
, 0, szwPathBuf
, *pcchPathBuf
, szPathBuf
,
7562 *pcchPathBuf
, NULL
, NULL
);
7564 HeapFree(GetProcessHeap(),0,szwFolder
);
7565 HeapFree(GetProcessHeap(),0,szwPathBuf
);
7570 UINT WINAPI
MsiGetTargetPathW( MSIHANDLE hInstall
, LPCWSTR szFolder
, LPWSTR
7571 szPathBuf
, DWORD
* pcchPathBuf
)
7574 UINT rc
= ERROR_FUNCTION_FAILED
;
7575 MSIPACKAGE
*package
;
7577 TRACE("(%s %p %li)\n",debugstr_w(szFolder
),szPathBuf
,*pcchPathBuf
);
7579 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
7581 return ERROR_INVALID_HANDLE
;
7582 path
= resolve_folder(package
, szFolder
, FALSE
, FALSE
, NULL
);
7583 msiobj_release( &package
->hdr
);
7585 if (path
&& (strlenW(path
) > *pcchPathBuf
))
7587 *pcchPathBuf
= strlenW(path
)+1;
7588 rc
= ERROR_MORE_DATA
;
7592 *pcchPathBuf
= strlenW(path
)+1;
7593 strcpyW(szPathBuf
,path
);
7594 TRACE("Returning Path %s\n",debugstr_w(path
));
7597 HeapFree(GetProcessHeap(),0,path
);
7603 UINT WINAPI
MsiGetSourcePathA( MSIHANDLE hInstall
, LPCSTR szFolder
,
7604 LPSTR szPathBuf
, DWORD
* pcchPathBuf
)
7610 TRACE("getting source %s %p %li\n",szFolder
,szPathBuf
, *pcchPathBuf
);
7613 return ERROR_FUNCTION_FAILED
;
7615 return ERROR_FUNCTION_FAILED
;
7617 szwFolder
= strdupAtoW(szFolder
);
7619 return ERROR_FUNCTION_FAILED
;
7621 szwPathBuf
= HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf
* sizeof(WCHAR
));
7623 rc
= MsiGetSourcePathW(hInstall
, szwFolder
, szwPathBuf
,pcchPathBuf
);
7625 WideCharToMultiByte( CP_ACP
, 0, szwPathBuf
, *pcchPathBuf
, szPathBuf
,
7626 *pcchPathBuf
, NULL
, NULL
);
7628 HeapFree(GetProcessHeap(),0,szwFolder
);
7629 HeapFree(GetProcessHeap(),0,szwPathBuf
);
7634 UINT WINAPI
MsiGetSourcePathW( MSIHANDLE hInstall
, LPCWSTR szFolder
, LPWSTR
7635 szPathBuf
, DWORD
* pcchPathBuf
)
7638 UINT rc
= ERROR_FUNCTION_FAILED
;
7639 MSIPACKAGE
*package
;
7641 TRACE("(%s %p %li)\n",debugstr_w(szFolder
),szPathBuf
,*pcchPathBuf
);
7643 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
7645 return ERROR_INVALID_HANDLE
;
7646 path
= resolve_folder(package
, szFolder
, TRUE
, FALSE
, NULL
);
7647 msiobj_release( &package
->hdr
);
7649 if (path
&& strlenW(path
) > *pcchPathBuf
)
7651 *pcchPathBuf
= strlenW(path
)+1;
7652 rc
= ERROR_MORE_DATA
;
7656 *pcchPathBuf
= strlenW(path
)+1;
7657 strcpyW(szPathBuf
,path
);
7658 TRACE("Returning Path %s\n",debugstr_w(path
));
7661 HeapFree(GetProcessHeap(),0,path
);
7667 /***********************************************************************
7668 * MsiSetTargetPathA (MSI.@)
7670 UINT WINAPI
MsiSetTargetPathA(MSIHANDLE hInstall
, LPCSTR szFolder
,
7671 LPCSTR szFolderPath
)
7674 LPWSTR szwFolderPath
;
7678 return ERROR_FUNCTION_FAILED
;
7680 return ERROR_FUNCTION_FAILED
;
7682 szwFolder
= strdupAtoW(szFolder
);
7684 return ERROR_FUNCTION_FAILED
;
7686 szwFolderPath
= strdupAtoW(szFolderPath
);
7689 HeapFree(GetProcessHeap(),0,szwFolder
);
7690 return ERROR_FUNCTION_FAILED
;
7693 rc
= MsiSetTargetPathW(hInstall
, szwFolder
, szwFolderPath
);
7695 HeapFree(GetProcessHeap(),0,szwFolder
);
7696 HeapFree(GetProcessHeap(),0,szwFolderPath
);
7701 UINT
MSI_SetTargetPathW(MSIPACKAGE
*package
, LPCWSTR szFolder
,
7702 LPCWSTR szFolderPath
)
7706 LPWSTR path2
= NULL
;
7709 TRACE("(%p %s %s)\n",package
, debugstr_w(szFolder
),debugstr_w(szFolderPath
));
7712 return ERROR_INVALID_HANDLE
;
7714 if (szFolderPath
[0]==0)
7715 return ERROR_FUNCTION_FAILED
;
7717 if (GetFileAttributesW(szFolderPath
) == INVALID_FILE_ATTRIBUTES
)
7718 return ERROR_FUNCTION_FAILED
;
7720 path
= resolve_folder(package
,szFolder
,FALSE
,FALSE
,&folder
);
7723 return ERROR_INVALID_PARAMETER
;
7725 HeapFree(GetProcessHeap(),0,folder
->Property
);
7726 folder
->Property
= build_directory_name(2, szFolderPath
, NULL
);
7728 if (lstrcmpiW(path
, folder
->Property
) == 0)
7731 * Resolved Target has not really changed, so just
7732 * set this folder and do not recalculate everything.
7734 HeapFree(GetProcessHeap(),0,folder
->ResolvedTarget
);
7735 folder
->ResolvedTarget
= NULL
;
7736 path2
= resolve_folder(package
,szFolder
,FALSE
,TRUE
,NULL
);
7737 HeapFree(GetProcessHeap(),0,path2
);
7741 for (i
= 0; i
< package
->loaded_folders
; i
++)
7743 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedTarget
);
7744 package
->folders
[i
].ResolvedTarget
=NULL
;
7747 for (i
= 0; i
< package
->loaded_folders
; i
++)
7749 path2
=resolve_folder(package
, package
->folders
[i
].Directory
, FALSE
,
7751 HeapFree(GetProcessHeap(),0,path2
);
7754 HeapFree(GetProcessHeap(),0,path
);
7756 return ERROR_SUCCESS
;
7759 /***********************************************************************
7760 * MsiSetTargetPathW (MSI.@)
7762 UINT WINAPI
MsiSetTargetPathW(MSIHANDLE hInstall
, LPCWSTR szFolder
,
7763 LPCWSTR szFolderPath
)
7765 MSIPACKAGE
*package
;
7768 TRACE("(%s %s)\n",debugstr_w(szFolder
),debugstr_w(szFolderPath
));
7770 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
7771 ret
= MSI_SetTargetPathW( package
, szFolder
, szFolderPath
);
7772 msiobj_release( &package
->hdr
);
7776 /***********************************************************************
7777 * MsiGetMode (MSI.@)
7779 * Returns an internal installer state (if it is running in a mode iRunMode)
7782 * hInstall [I] Handle to the installation
7783 * hRunMode [I] Checking run mode
7784 * MSIRUNMODE_ADMIN Administrative mode
7785 * MSIRUNMODE_ADVERTISE Advertisement mode
7786 * MSIRUNMODE_MAINTENANCE Maintenance mode
7787 * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled
7788 * MSIRUNMODE_LOGENABLED Log file is writing
7789 * MSIRUNMODE_OPERATIONS Operations in progress??
7790 * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed
7791 * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation
7792 * MSIRUNMODE_CABINET Files from cabinet are installed
7793 * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is suppressed
7794 * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is suppressed
7795 * MSIRUNMODE_RESERVED11 Reserved
7796 * MSIRUNMODE_WINDOWS9X Running under Windows95/98
7797 * MSIRUNMODE_ZAWENABLED Demand installation is supported
7798 * MSIRUNMODE_RESERVED14 Reserved
7799 * MSIRUNMODE_RESERVED15 Reserved
7800 * MSIRUNMODE_SCHEDULED called from install script
7801 * MSIRUNMODE_ROLLBACK called from rollback script
7802 * MSIRUNMODE_COMMIT called from commit script
7805 * In the state: TRUE
7806 * Not in the state: FALSE
7810 BOOL WINAPI
MsiGetMode(MSIHANDLE hInstall
, MSIRUNMODE iRunMode
)
7812 FIXME("STUB (iRunMode=%i)\n",iRunMode
);
7816 /***********************************************************************
7817 * MsiSetFeatureStateA (MSI.@)
7819 * According to the docs, when this is called it immediately recalculates
7820 * all the component states as well
7822 UINT WINAPI
MsiSetFeatureStateA(MSIHANDLE hInstall
, LPCSTR szFeature
,
7823 INSTALLSTATE iState
)
7825 LPWSTR szwFeature
= NULL
;
7828 szwFeature
= strdupAtoW(szFeature
);
7831 return ERROR_FUNCTION_FAILED
;
7833 rc
= MsiSetFeatureStateW(hInstall
,szwFeature
, iState
);
7835 HeapFree(GetProcessHeap(),0,szwFeature
);
7842 UINT WINAPI
MSI_SetFeatureStateW(MSIPACKAGE
* package
, LPCWSTR szFeature
,
7843 INSTALLSTATE iState
)
7846 UINT rc
= ERROR_SUCCESS
;
7848 TRACE(" %s to %i\n",debugstr_w(szFeature
), iState
);
7850 index
= get_loaded_feature(package
,szFeature
);
7852 return ERROR_UNKNOWN_FEATURE
;
7854 if (iState
== INSTALLSTATE_ADVERTISED
&&
7855 package
->features
[index
].Attributes
&
7856 msidbFeatureAttributesDisallowAdvertise
)
7857 return ERROR_FUNCTION_FAILED
;
7859 package
->features
[index
].ActionRequest
= iState
;
7860 package
->features
[index
].Action
= iState
;
7862 ACTION_UpdateComponentStates(package
,szFeature
);
7864 /* update all the features that are children of this feature */
7865 for (i
= 0; i
< package
->loaded_features
; i
++)
7867 if (strcmpW(szFeature
, package
->features
[i
].Feature_Parent
) == 0)
7868 MSI_SetFeatureStateW(package
, package
->features
[i
].Feature
, iState
);
7874 /***********************************************************************
7875 * MsiSetFeatureStateW (MSI.@)
7877 UINT WINAPI
MsiSetFeatureStateW(MSIHANDLE hInstall
, LPCWSTR szFeature
,
7878 INSTALLSTATE iState
)
7880 MSIPACKAGE
* package
;
7881 UINT rc
= ERROR_SUCCESS
;
7883 TRACE(" %s to %i\n",debugstr_w(szFeature
), iState
);
7885 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
7887 return ERROR_INVALID_HANDLE
;
7889 rc
= MSI_SetFeatureStateW(package
,szFeature
,iState
);
7891 msiobj_release( &package
->hdr
);
7895 UINT WINAPI
MsiGetFeatureStateA(MSIHANDLE hInstall
, LPSTR szFeature
,
7896 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
7898 LPWSTR szwFeature
= NULL
;
7901 szwFeature
= strdupAtoW(szFeature
);
7903 rc
= MsiGetFeatureStateW(hInstall
,szwFeature
,piInstalled
, piAction
);
7905 HeapFree( GetProcessHeap(), 0 , szwFeature
);
7910 UINT
MSI_GetFeatureStateW(MSIPACKAGE
*package
, LPWSTR szFeature
,
7911 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
7915 index
= get_loaded_feature(package
,szFeature
);
7917 return ERROR_UNKNOWN_FEATURE
;
7920 *piInstalled
= package
->features
[index
].Installed
;
7923 *piAction
= package
->features
[index
].Action
;
7925 TRACE("returning %i %i\n",*piInstalled
,*piAction
);
7927 return ERROR_SUCCESS
;
7930 UINT WINAPI
MsiGetFeatureStateW(MSIHANDLE hInstall
, LPWSTR szFeature
,
7931 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
7933 MSIPACKAGE
* package
;
7936 TRACE("%ld %s %p %p\n", hInstall
, debugstr_w(szFeature
), piInstalled
,
7939 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
7941 return ERROR_INVALID_HANDLE
;
7942 ret
= MSI_GetFeatureStateW(package
, szFeature
, piInstalled
, piAction
);
7943 msiobj_release( &package
->hdr
);
7947 /***********************************************************************
7948 * MsiGetComponentStateA (MSI.@)
7950 UINT WINAPI
MsiGetComponentStateA(MSIHANDLE hInstall
, LPSTR szComponent
,
7951 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
7953 LPWSTR szwComponent
= NULL
;
7956 szwComponent
= strdupAtoW(szComponent
);
7958 rc
= MsiGetComponentStateW(hInstall
,szwComponent
,piInstalled
, piAction
);
7960 HeapFree( GetProcessHeap(), 0 , szwComponent
);
7965 UINT
MSI_GetComponentStateW(MSIPACKAGE
*package
, LPWSTR szComponent
,
7966 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
7970 TRACE("%p %s %p %p\n", package
, debugstr_w(szComponent
), piInstalled
,
7973 index
= get_loaded_component(package
,szComponent
);
7975 return ERROR_UNKNOWN_COMPONENT
;
7978 *piInstalled
= package
->components
[index
].Installed
;
7981 *piAction
= package
->components
[index
].Action
;
7983 TRACE("states (%i, %i)\n",
7984 (piInstalled
)?*piInstalled
:-1,(piAction
)?*piAction
:-1);
7986 return ERROR_SUCCESS
;
7989 /***********************************************************************
7990 * MsiGetComponentStateW (MSI.@)
7992 UINT WINAPI
MsiGetComponentStateW(MSIHANDLE hInstall
, LPWSTR szComponent
,
7993 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
7995 MSIPACKAGE
* package
;
7998 TRACE("%ld %s %p %p\n", hInstall
, debugstr_w(szComponent
),
7999 piInstalled
, piAction
);
8001 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
8003 return ERROR_INVALID_HANDLE
;
8004 ret
= MSI_GetComponentStateW( package
, szComponent
, piInstalled
, piAction
);
8005 msiobj_release( &package
->hdr
);