Avoid a loop where a parent's parent refers to itself as its parent.
[wine/wine-kai.git] / dlls / msi / action.c
blobe71f13e1ac14399845e80134abe9930aa9a43e7a
1 /*
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
22 * Pages I need
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
29 #include <stdarg.h>
30 #include <stdio.h>
32 #define COBJMACROS
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winreg.h"
38 #include "wine/debug.h"
39 #include "fdi.h"
40 #include "msi.h"
41 #include "msiquery.h"
42 #include "msidefs.h"
43 #include "msvcrt/fcntl.h"
44 #include "objbase.h"
45 #include "objidl.h"
46 #include "msipriv.h"
47 #include "winnls.h"
48 #include "winuser.h"
49 #include "shlobj.h"
50 #include "wine/unicode.h"
51 #include "winver.h"
52 #include "action.h"
54 #define REG_PROGRESS_VALUE 13200
55 #define COMPONENT_PROGRESS_VALUE 24000
57 WINE_DEFAULT_DEBUG_CHANNEL(msi);
60 * Prototypes
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,
66 LPWSTR *FilePath);
68 /*
69 * action handlers
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',
193 'F','i','l','e',0};
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',
219 'I','n','f','o',0};
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',
267 'I','n','f','o',0};
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',
279 'I','n','f','o',0};
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};
289 struct _actions {
290 LPCWSTR action;
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},
370 { NULL, NULL},
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,'|');
380 if (p)
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,'|');
387 if (p)
388 *p = 0;
391 WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
393 UINT rc;
394 DWORD sz;
395 LPWSTR ret;
397 sz = 0;
398 if (MSI_RecordIsNull(row,index))
399 return NULL;
401 rc = MSI_RecordGetStringW(row,index,NULL,&sz);
403 /* having an empty string is different than NULL */
404 if (sz == 0)
406 ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR));
407 ret[0] = 0;
408 return ret;
411 sz ++;
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);
418 ret = NULL;
420 return ret;
423 LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc)
425 DWORD sz = 0;
426 LPWSTR str;
427 UINT r;
429 r = MSI_GetPropertyW(package, prop, NULL, &sz);
430 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
432 if (rc)
433 *rc = r;
434 return NULL;
436 sz++;
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);
442 str = NULL;
444 if (rc)
445 *rc = r;
446 return str;
449 int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
451 int rc = -1;
452 DWORD i;
454 for (i = 0; i < package->loaded_components; i++)
456 if (strcmpW(Component,package->components[i].Component)==0)
458 rc = i;
459 break;
462 return rc;
465 int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
467 int rc = -1;
468 DWORD i;
470 for (i = 0; i < package->loaded_features; i++)
472 if (strcmpW(Feature,package->features[i].Feature)==0)
474 rc = i;
475 break;
478 return rc;
481 int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
483 int rc = -1;
484 DWORD i;
486 for (i = 0; i < package->loaded_files; i++)
488 if (strcmpW(file,package->files[i].File)==0)
490 rc = i;
491 break;
494 return rc;
497 int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
499 DWORD i;
500 DWORD index;
502 if (!package)
503 return -2;
505 for (i=0; i < package->loaded_files; i++)
506 if (strcmpW(package->files[i].File,name)==0)
507 return -1;
509 index = package->loaded_files;
510 package->loaded_files++;
511 if (package->loaded_files== 1)
512 package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
513 else
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));
525 return 0;
528 static void remove_tracked_tempfiles(MSIPACKAGE* package)
530 DWORD i;
532 if (!package)
533 return;
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 )
549 if (ptr)
551 MSIRECORD *rec = MSI_CreateRecord(1);
552 DWORD size = 0;
554 MSI_RecordSetStringW(rec,0,ptr);
555 MSI_FormatRecordW(package,rec,NULL,&size);
556 if (size >= 0)
558 size++;
559 *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
560 if (size > 1)
561 MSI_FormatRecordW(package,rec,*data,&size);
562 else
563 *data[0] = 0;
564 msiobj_release( &rec->hdr );
565 return sizeof(WCHAR)*size;
567 msiobj_release( &rec->hdr );
570 *data = NULL;
571 return 0;
574 DWORD build_version_dword(LPCWSTR version_string)
576 SHORT major,minor;
577 WORD build;
578 DWORD rc = 0x00000000;
579 LPCWSTR ptr1;
581 ptr1 = version_string;
583 if (!ptr1)
584 return rc;
585 else
586 major = atoiW(ptr1);
589 if(ptr1)
590 ptr1 = strchrW(ptr1,'.');
591 if (ptr1)
593 ptr1++;
594 minor = atoiW(ptr1);
596 else
597 minor = 0;
599 if (ptr1)
600 ptr1 = strchrW(ptr1,'.');
602 if (ptr1)
604 ptr1++;
605 build = atoiW(ptr1);
607 else
608 build = 0;
610 rc = MAKELONG(build,MAKEWORD(minor,major));
611 TRACE("%s -> 0x%lx\n",debugstr_w(version_string),rc);
612 return rc;
615 /* Called when the package is being closed */
616 void ACTION_free_package_structures( MSIPACKAGE* package)
618 INT i;
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);
720 if (package->script)
722 for (i = 0; i < TOTAL_SCRIPTS; i++)
724 int j;
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};
743 MSIRECORD *row;
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 )
753 MSIRECORD * row;
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};
773 WCHAR message[1024];
774 MSIRECORD * row = 0;
775 DWORD size;
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);
782 if (!row)
783 return;
785 if (MSI_RecordIsNull(row,3))
787 msiobj_release(&row->hdr);
788 return;
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);
802 size = 1024;
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',
820 '.',0};
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};
828 WCHAR message[1024];
829 WCHAR timet[0x100];
830 MSIRECORD * row = 0;
831 LPCWSTR ActionText;
833 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
835 row = MSI_QueryGetRecord( package->db, Query_t, action );
836 if (!row)
837 return;
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,
852 UINT rc)
854 MSIRECORD * row;
855 static const WCHAR template_s[]=
856 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
857 '%','s', '.',0};
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',' ',
861 '%','i','.',0};
862 static const WCHAR format[] =
863 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
864 WCHAR message[1024];
865 WCHAR timet[0x100];
867 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
868 if (start)
869 sprintfW(message,template_s,timet,action);
870 else
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, ...)
902 DWORD sz = 1, i;
903 LPWSTR dir;
904 va_list va;
906 va_start(va,count);
907 for(i=0; i<count; i++)
909 LPCWSTR str = va_arg(va,LPCWSTR);
910 if (str)
911 sz += strlenW(str) + 1;
913 va_end(va);
915 dir = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
916 dir[0]=0;
918 va_start(va,count);
919 for(i=0; i<count; i++)
921 LPCWSTR str = va_arg(va,LPCWSTR);
922 if (!str)
923 continue;
924 strcatW(dir, str);
925 if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\\')
926 strcatW(dir, cszbs);
928 return dir;
931 static BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, INT index,
932 INSTALLSTATE check )
934 if (package->components[index].Installed == check)
935 return FALSE;
937 if (package->components[index].ActionRequest == check)
938 return TRUE;
939 else
940 return FALSE;
943 static BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE* package, INT index,
944 INSTALLSTATE check )
946 if (package->features[index].Installed == check)
947 return FALSE;
949 if (package->features[index].ActionRequest == check)
950 return TRUE;
951 else
952 return FALSE;
956 /****************************************************
957 * TOP level entry points
958 *****************************************************/
960 UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
961 LPCWSTR szCommandLine)
963 DWORD sz;
964 WCHAR buffer[10];
965 UINT rc;
966 BOOL ui = FALSE;
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));
976 if (szPackagePath)
978 LPWSTR p, check, path;
980 package->PackagePath = strdupW(szPackagePath);
981 path = strdupW(szPackagePath);
982 p = strrchrW(path,'\\');
983 if (p)
985 p++;
986 *p=0;
988 else
990 HeapFree(GetProcessHeap(),0,path);
991 path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR));
992 GetCurrentDirectoryW(MAX_PATH,path);
993 strcatW(path,cszbs);
996 check = load_dynamic_property(package, cszSourceDir,NULL);
997 if (!check)
998 MSI_SetPropertyW(package, cszSourceDir, path);
999 else
1000 HeapFree(GetProcessHeap(), 0, check);
1002 HeapFree(GetProcessHeap(), 0, path);
1005 if (szCommandLine)
1007 LPWSTR ptr,ptr2;
1008 ptr = (LPWSTR)szCommandLine;
1010 while (*ptr)
1012 WCHAR *prop = NULL;
1013 WCHAR *val = NULL;
1015 TRACE("Looking at %s\n",debugstr_w(ptr));
1017 ptr2 = strchrW(ptr,'=');
1018 if (ptr2)
1020 BOOL quote=FALSE;
1021 DWORD len = 0;
1023 while (*ptr == ' ') ptr++;
1024 len = ptr2-ptr;
1025 prop = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
1026 memcpy(prop,ptr,len*sizeof(WCHAR));
1027 prop[len]=0;
1028 ptr2++;
1030 len = 0;
1031 ptr = ptr2;
1032 while (*ptr && (quote || (!quote && *ptr!=' ')))
1034 if (*ptr == '"')
1035 quote = !quote;
1036 ptr++;
1037 len++;
1040 if (*ptr2=='"')
1042 ptr2++;
1043 len -= 2;
1045 val = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
1046 memcpy(val,ptr2,len*sizeof(WCHAR));
1047 val[len] = 0;
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);
1058 ptr++;
1062 sz = 10;
1063 if (MSI_GetPropertyW(package,szUILevel,buffer,&sz) == ERROR_SUCCESS)
1065 if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED)
1067 rc = ACTION_ProcessUISequence(package);
1068 ui = TRUE;
1069 if (rc == ERROR_SUCCESS)
1070 rc = ACTION_ProcessExecSequence(package,TRUE);
1072 else
1073 rc = ACTION_ProcessExecSequence(package,FALSE);
1075 else
1076 rc = ACTION_ProcessExecSequence(package,FALSE);
1078 if (rc == -1)
1080 /* install was halted but should be considered a success */
1081 rc = ERROR_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);
1093 else /* failed */
1094 ACTION_PerformActionSequence(package,-3,ui);
1096 /* finish up running custom actions */
1097 ACTION_FinishCustomActions(package);
1099 return rc;
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};
1118 if (UI)
1119 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
1120 else
1121 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
1123 if (row)
1125 LPCWSTR action, cond;
1127 TRACE("Running the actions\n");
1129 /* check conditions */
1130 cond = MSI_RecordGetString(row,2);
1131 if (cond)
1133 /* this is a hack to skip errors in the condition code */
1134 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
1135 goto end;
1138 action = MSI_RecordGetString(row,1);
1139 if (!action)
1141 ERR("failed to fetch action\n");
1142 rc = ERROR_FUNCTION_FAILED;
1143 goto end;
1146 if (UI)
1147 rc = ACTION_PerformUIAction(package,action);
1148 else
1149 rc = ACTION_PerformAction(package,action,FALSE);
1150 end:
1151 msiobj_release(&row->hdr);
1153 else
1154 rc = ERROR_SUCCESS;
1156 return rc;
1159 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
1161 MSIQUERY * view;
1162 UINT rc;
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};
1178 INT seq = 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 */
1190 if (UIran)
1192 row = MSI_QueryGetRecord(package->db, IVQuery);
1193 if( !row )
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);
1208 goto end;
1211 TRACE("Running the actions\n");
1213 while (1)
1215 LPCWSTR cond, action;
1217 rc = MSI_ViewFetch(view,&row);
1218 if (rc != ERROR_SUCCESS)
1220 rc = ERROR_SUCCESS;
1221 break;
1224 action = MSI_RecordGetString(row,1);
1225 if (!action)
1227 rc = ERROR_FUNCTION_FAILED;
1228 msiobj_release(&row->hdr);
1229 break;
1232 /* check conditions */
1233 cond = MSI_RecordGetString(row,2);
1234 if (cond)
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));
1242 continue;
1246 rc = ACTION_PerformAction(package,action,FALSE);
1248 if (rc == ERROR_FUNCTION_NOT_CALLED)
1249 rc = ERROR_SUCCESS;
1251 if (rc != ERROR_SUCCESS)
1253 ERR("Execution halted due to error (%i)\n",rc);
1254 msiobj_release(&row->hdr);
1255 break;
1258 msiobj_release(&row->hdr);
1261 MSI_ViewClose(view);
1262 msiobj_release(&view->hdr);
1265 end:
1266 return rc;
1270 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1272 MSIQUERY * view;
1273 UINT rc;
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);
1293 goto end;
1296 TRACE("Running the actions \n");
1298 while (1)
1300 LPCWSTR action, cond;
1301 MSIRECORD * row = 0;
1303 rc = MSI_ViewFetch(view,&row);
1304 if (rc != ERROR_SUCCESS)
1306 rc = ERROR_SUCCESS;
1307 break;
1310 action = MSI_RecordGetString(row,1);
1311 if (!action)
1313 ERR("failed to fetch action\n");
1314 rc = ERROR_FUNCTION_FAILED;
1315 msiobj_release(&row->hdr);
1316 break;
1319 /* check conditions */
1320 cond = MSI_RecordGetString(row,2);
1321 if (cond)
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));
1329 continue;
1333 rc = ACTION_PerformUIAction(package,action);
1335 if (rc == ERROR_FUNCTION_NOT_CALLED)
1336 rc = ERROR_SUCCESS;
1338 if (rc != ERROR_SUCCESS)
1340 ERR("Execution halted due to error (%i)\n",rc);
1341 msiobj_release(&row->hdr);
1342 break;
1345 msiobj_release(&row->hdr);
1348 MSI_ViewClose(view);
1349 msiobj_release(&view->hdr);
1352 end:
1353 return rc;
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 )
1362 BOOL ret = FALSE;
1363 BOOL run = force;
1364 int i;
1366 if (!run && !package->script->CurrentlyScripting)
1367 run = TRUE;
1369 if (!run)
1371 if (strcmpW(action,szInstallFinalize) == 0 ||
1372 strcmpW(action,szInstallExecute) == 0 ||
1373 strcmpW(action,szInstallExecuteAgain) == 0)
1374 run = TRUE;
1377 i = 0;
1378 while (StandardActions[i].action != NULL)
1380 if (strcmpW(StandardActions[i].action, action)==0)
1382 ce_actiontext(package, action);
1383 if (!run)
1385 ui_actioninfo(package, action, TRUE, 0);
1386 *rc = schedule_action(package,INSTALL_SCRIPT,action);
1387 ui_actioninfo(package, action, FALSE, *rc);
1389 else
1391 ui_actionstart(package, action);
1392 if (StandardActions[i].handler)
1394 *rc = StandardActions[i].handler(package);
1396 else
1398 FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action));
1399 *rc = ERROR_SUCCESS;
1402 ret = TRUE;
1403 break;
1405 i++;
1407 return ret;
1410 static BOOL ACTION_HandleDialogBox( MSIPACKAGE *package, LPCWSTR dialog, UINT* rc )
1412 BOOL ret = FALSE;
1414 if (ACTION_DialogBox(package,dialog) == ERROR_SUCCESS)
1416 *rc = package->CurrentInstallState;
1417 ret = TRUE;
1419 return ret;
1422 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1423 UINT* rc, BOOL force )
1425 BOOL ret=FALSE;
1426 UINT arc;
1428 arc = ACTION_CustomAction(package,action, force);
1430 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1432 *rc = arc;
1433 ret = TRUE;
1435 return ret;
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;
1449 BOOL handled;
1451 TRACE("Performing action (%s)\n",debugstr_w(action));
1453 handled = ACTION_HandleStandardAction(package, action, &rc, force);
1455 if (!handled)
1456 handled = ACTION_HandleCustomAction(package, action, &rc, force);
1458 if (!handled)
1460 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
1461 rc = ERROR_FUNCTION_NOT_CALLED;
1464 package->CurrentInstallState = rc;
1465 return 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);
1477 if (!handled)
1478 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1480 if (!handled)
1481 handled = ACTION_HandleDialogBox(package, action, &rc);
1483 msi_dialog_check_messages( NULL );
1485 if (!handled)
1487 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
1488 rc = ERROR_FUNCTION_NOT_CALLED;
1491 package->CurrentInstallState = rc;
1492 return rc;
1495 /***********************************************************************
1496 * create_full_pathW
1498 * Recursively create all directories in the path.
1500 * shamelessly stolen from setupapi/queue.c
1502 static BOOL create_full_pathW(const WCHAR *path)
1504 BOOL ret = TRUE;
1505 int len;
1506 WCHAR *new_path;
1508 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *
1509 sizeof(WCHAR));
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))
1518 WCHAR *slash;
1519 DWORD last_error = GetLastError();
1520 if(last_error == ERROR_ALREADY_EXISTS)
1521 break;
1523 if(last_error != ERROR_PATH_NOT_FOUND)
1525 ret = FALSE;
1526 break;
1529 if(!(slash = strrchrW(new_path, '\\')))
1531 ret = FALSE;
1532 break;
1535 len = slash - new_path;
1536 new_path[len] = 0;
1537 if(!create_full_pathW(new_path))
1539 ret = FALSE;
1540 break;
1542 new_path[len] = '\\';
1545 HeapFree(GetProcessHeap(), 0, new_path);
1546 return ret;
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 };
1560 UINT rc;
1561 MSIQUERY *view;
1562 MSIFOLDER *folder;
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);
1573 return rc;
1576 while (1)
1578 LPCWSTR dir;
1579 LPWSTR full_path;
1580 MSIRECORD *row = NULL, *uirow;
1582 rc = MSI_ViewFetch(view,&row);
1583 if (rc != ERROR_SUCCESS)
1585 rc = ERROR_SUCCESS;
1586 break;
1589 dir = MSI_RecordGetString(row,1);
1590 if (!dir)
1592 ERR("Unable to get folder id \n");
1593 msiobj_release(&row->hdr);
1594 continue;
1597 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1598 if (!full_path)
1600 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1601 msiobj_release(&row->hdr);
1602 continue;
1605 TRACE("Folder is %s\n",debugstr_w(full_path));
1607 /* UI stuff */
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);
1616 folder->State = 3;
1618 msiobj_release(&row->hdr);
1619 HeapFree(GetProcessHeap(),0,full_path);
1621 MSI_ViewClose(view);
1622 msiobj_release(&view->hdr);
1624 return rc;
1627 static int load_component(MSIPACKAGE* package, MSIRECORD * row)
1629 int index = package->loaded_components;
1630 DWORD sz;
1632 /* fill in the data */
1634 package->loaded_components++;
1635 if (package->loaded_components == 1)
1636 package->components = HeapAlloc(GetProcessHeap(),0,
1637 sizeof(MSICOMPONENT));
1638 else
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));
1651 sz = 0x100;
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);
1660 sz = 0x100;
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;
1672 return index;
1675 static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
1677 int index = package->loaded_features;
1678 DWORD sz;
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};
1692 MSIQUERY * view;
1693 MSIQUERY * view2;
1694 MSIRECORD * row2;
1695 MSIRECORD * row3;
1696 UINT rc;
1698 /* fill in the data */
1700 package->loaded_features ++;
1701 if (package->loaded_features == 1)
1702 package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE));
1703 else
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);
1718 sz = 0x100;
1719 if (!MSI_RecordIsNull(row,3))
1720 MSI_RecordGetStringW(row,3,package->features[index].Title,&sz);
1722 sz = 0x100;
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)
1745 return;
1746 rc = MSI_ViewExecute(view,0);
1747 if (rc != ERROR_SUCCESS)
1749 MSI_ViewClose(view);
1750 msiobj_release(&view->hdr);
1751 return;
1753 while (1)
1755 LPCWSTR component;
1756 DWORD rc;
1757 INT c_indx;
1758 INT cnt = package->features[index].ComponentCount;
1760 rc = MSI_ViewFetch(view,&row2);
1761 if (rc != ERROR_SUCCESS)
1762 break;
1764 component = MSI_RecordGetString(row2,1);
1766 /* check to see if the component is already loaded */
1767 c_indx = get_loaded_component(package,component);
1768 if (c_indx != -1)
1770 TRACE("Component %s already loaded at %i\n", debugstr_w(component),
1771 c_indx);
1772 package->features[index].Components[cnt] = c_indx;
1773 package->features[index].ComponentCount ++;
1774 msiobj_release( &row2->hdr );
1775 continue;
1778 rc = MSI_OpenQuery(package->db, &view2, Query2, component);
1779 if (rc != ERROR_SUCCESS)
1781 msiobj_release( &row2->hdr );
1782 continue;
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 );
1790 continue;
1792 while (1)
1794 DWORD rc;
1796 rc = MSI_ViewFetch(view2,&row3);
1797 if (rc != ERROR_SUCCESS)
1798 break;
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;
1817 DWORD i;
1818 LPWSTR buffer;
1820 /* fill in the data */
1822 package->loaded_files++;
1823 if (package->loaded_files== 1)
1824 package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
1825 else
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;
1839 break;
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)
1867 MSIQUERY * view;
1868 MSIRECORD * row;
1869 UINT rc;
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};
1875 if (!package)
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;
1890 while (1)
1892 rc = MSI_ViewFetch(view,&row);
1893 if (rc != ERROR_SUCCESS)
1895 rc = ERROR_SUCCESS;
1896 break;
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
1919 * directory table.
1921 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1923 MSIQUERY * view;
1924 MSIRECORD * row;
1925 UINT rc;
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 };
1932 WCHAR buffer[3];
1933 DWORD sz = 3;
1935 MSI_GetPropertyW(package, szCosting, buffer, &sz);
1936 if (buffer[0]=='1')
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)
1944 return rc;
1945 rc = MSI_ViewExecute(view,0);
1946 if (rc != ERROR_SUCCESS)
1948 MSI_ViewClose(view);
1949 msiobj_release(&view->hdr);
1950 return rc;
1952 while (1)
1954 DWORD rc;
1956 rc = MSI_ViewFetch(view,&row);
1957 if (rc != ERROR_SUCCESS)
1958 break;
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)
1973 UINT count;
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]++;
1984 if (count != 0)
1985 newbuf = HeapReAlloc(GetProcessHeap(),0,
1986 package->script->Actions[script],
1987 package->script->ActionCount[script]* sizeof(LPWSTR));
1988 else
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 )
1999 int i;
2000 UINT rc = ERROR_SUCCESS;
2002 TRACE("Executing Script %i\n",script);
2004 for (i = 0; i < package->script->ActionCount[script]; i++)
2006 LPWSTR action;
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)
2013 break;
2015 HeapFree(GetProcessHeap(),0,package->script->Actions[script]);
2017 package->script->ActionCount[script] = 0;
2018 package->script->Actions[script] = NULL;
2019 return rc;
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;
2039 INT index = -1;
2040 DWORD i;
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);
2049 return 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,
2058 sizeof(MSIFOLDER));
2059 else
2060 package->folders= HeapReAlloc(GetProcessHeap(),0,
2061 package->folders, package->loaded_folders*
2062 sizeof(MSIFOLDER));
2064 memset(&package->folders[index],0,sizeof(MSIFOLDER));
2066 package->folders[index].Directory = strdupW(dir);
2068 row = MSI_QueryGetRecord(package->db, Query, dir);
2069 if (!row)
2070 return -1;
2072 ptargetdir = targetdir = load_dynamic_stringW(row,3);
2074 /* split src and target dir */
2075 if (strchrW(targetdir,':'))
2077 srcdir=strchrW(targetdir,':');
2078 *srcdir=0;
2079 srcdir ++;
2081 else
2082 srcdir=NULL;
2084 /* for now only pick long filename versions */
2085 if (strchrW(targetdir,'|'))
2087 shortname = targetdir;
2088 targetdir = strchrW(targetdir,'|');
2089 *targetdir = 0;
2090 targetdir ++;
2092 /* for the sourcedir pick the short filename */
2093 if (srcdir && strchrW(srcdir,'|'))
2095 LPWSTR p = strchrW(srcdir,'|');
2096 *p = 0;
2099 /* now check for root dirs */
2100 if (targetdir[0] == '.' && targetdir[1] == 0)
2101 targetdir = NULL;
2103 if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
2104 srcdir = NULL;
2106 if (targetdir)
2108 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
2109 HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault);
2110 package->folders[index].TargetDefault = strdupW(targetdir);
2113 if (srcdir)
2114 package->folders[index].SourceDefault = strdupW(srcdir);
2115 else if (shortname)
2116 package->folders[index].SourceDefault = strdupW(shortname);
2117 else if (targetdir)
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);
2123 if (parent)
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));
2132 else
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);
2140 return index;
2144 LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
2145 BOOL set_prop, MSIFOLDER **folder)
2147 DWORD i;
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)
2155 if (!source)
2157 path = load_dynamic_property(package,cszTargetDir,NULL);
2158 if (!path)
2160 path = load_dynamic_property(package,cszRootDrive,NULL);
2161 if (set_prop)
2162 MSI_SetPropertyW(package,cszTargetDir,path);
2164 if (folder)
2166 for (i = 0; i < package->loaded_folders; i++)
2168 if (strcmpW(package->folders[i].Directory,name)==0)
2169 break;
2171 *folder = &(package->folders[i]);
2173 return path;
2175 else
2177 path = load_dynamic_property(package,cszSourceDir,NULL);
2178 if (!path)
2180 path = load_dynamic_property(package,cszDatabase,NULL);
2181 if (path)
2183 p = strrchrW(path,'\\');
2184 if (p)
2185 *(p+1) = 0;
2188 if (folder)
2190 for (i = 0; i < package->loaded_folders; i++)
2192 if (strcmpW(package->folders[i].Directory,name)==0)
2193 break;
2195 *folder = &(package->folders[i]);
2197 return path;
2201 for (i = 0; i < package->loaded_folders; i++)
2203 if (strcmpW(package->folders[i].Directory,name)==0)
2204 break;
2207 if (i >= package->loaded_folders)
2208 return NULL;
2210 if (folder)
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));
2217 return 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));
2223 return 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));
2230 if (set_prop)
2231 MSI_SetPropertyW(package,name,path);
2232 return 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);
2242 if (!source)
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));
2248 if (set_prop)
2249 MSI_SetPropertyW(package,name,path);
2251 else
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);
2259 return path;
2262 /* scan for and update current install states */
2263 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
2265 int i;
2266 LPWSTR productcode;
2268 productcode = load_dynamic_property(package,szProductCode,NULL);
2270 for (i = 0; i < package->loaded_components; i++)
2272 INSTALLSTATE res;
2273 res = MsiGetComponentPathW(productcode,
2274 package->components[i].ComponentId , NULL, NULL);
2275 if (res < 0)
2276 res = INSTALLSTATE_ABSENT;
2277 package->components[i].Installed = res;
2280 for (i = 0; i < package->loaded_features; i++)
2282 INSTALLSTATE res = -10;
2283 int j;
2284 for (j = 0; j < package->features[i].ComponentCount; j++)
2286 MSICOMPONENT* component = &package->components[package->features[i].
2287 Components[j]];
2288 if (res == -10)
2289 res = component->Installed;
2290 else
2292 if (res == component->Installed)
2293 continue;
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)
2305 int i;
2306 INSTALLSTATE newstate;
2307 MSIFEATURE *feature;
2309 i = get_loaded_feature(package,szFeature);
2310 if (i < 0)
2311 return;
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)
2325 continue;
2326 else
2328 if (newstate == INSTALLSTATE_LOCAL)
2330 component->ActionRequest = INSTALLSTATE_LOCAL;
2331 component->Action = INSTALLSTATE_LOCAL;
2333 else
2335 int j,k;
2337 component->ActionRequest = newstate;
2338 component->Action = newstate;
2340 /*if any other feature wants is local we need to set it local*/
2341 for (j = 0;
2342 j < package->loaded_features &&
2343 component->ActionRequest != INSTALLSTATE_LOCAL;
2344 j++)
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 ==
2351 INSTALLSTATE_LOCAL)
2353 TRACE("Saved by %s\n", debugstr_w(package->features[j].Feature));
2354 component->ActionRequest = INSTALLSTATE_LOCAL;
2355 component->Action = INSTALLSTATE_LOCAL;
2357 break;
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,
2369 INSTALLSTATE state)
2371 static const WCHAR all[]={'A','L','L',0};
2372 LPWSTR override = NULL;
2373 INT i;
2374 BOOL rc = FALSE;
2376 override = load_dynamic_property(package, property, NULL);
2377 if (override)
2379 rc = TRUE;
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;
2387 else
2389 LPWSTR ptr = override;
2390 LPWSTR ptr2 = strchrW(override,',');
2392 while (ptr)
2394 if ((ptr2 &&
2395 strncmpW(ptr,package->features[i].Feature, ptr2-ptr)==0)
2396 || (!ptr2 &&
2397 strcmpW(ptr,package->features[i].Feature)==0))
2399 package->features[i].ActionRequest= state;
2400 package->features[i].Action = state;
2401 break;
2403 if (ptr2)
2405 ptr=ptr2+1;
2406 ptr2 = strchrW(ptr,',');
2408 else
2409 break;
2413 HeapFree(GetProcessHeap(),0,override);
2416 return rc;
2419 static UINT SetFeatureStates(MSIPACKAGE *package)
2421 LPWSTR level;
2422 INT install_level;
2423 DWORD i;
2424 INT j;
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);
2438 if (level)
2440 install_level = atoiW(level);
2441 HeapFree(GetProcessHeap(), 0, level);
2443 else
2444 install_level = 1;
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
2450 * 2) ADDLOCAL
2451 * 3) REMOVE
2452 * 4) ADDSOURCE
2453 * 5) ADDDEFAULT
2454 * 6) REINSTALL
2455 * 7) COMPADDLOCAL
2456 * 8) COMPADDSOURCE
2457 * 9) FILEADDLOCAL
2458 * 10) FILEADDSOURCE
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
2466 * yet anyway.
2468 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
2469 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
2471 if (!override)
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;
2493 else
2495 package->features[i].ActionRequest = INSTALLSTATE_LOCAL;
2496 package->features[i].Action = INSTALLSTATE_LOCAL;
2501 else
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;
2531 else
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 };
2603 UINT rc;
2604 MSIQUERY * view;
2605 DWORD i;
2606 LPWSTR level;
2607 DWORD sz = 3;
2608 WCHAR buffer[3];
2610 MSI_GetPropertyW(package, szCosting, buffer, &sz);
2611 if (buffer[0]=='1')
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);
2624 return rc;
2627 while (1)
2629 LPCWSTR name;
2630 LPWSTR path;
2631 MSIRECORD * row = 0;
2633 rc = MSI_ViewFetch(view,&row);
2634 if (rc != ERROR_SUCCESS)
2636 rc = ERROR_SUCCESS;
2637 break;
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)
2667 continue;
2669 if (comp)
2671 LPWSTR p;
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)
2690 file->State = 1;
2691 comp->Cost += file->FileSize;
2693 else
2695 if (file->Version)
2697 DWORD handle;
2698 DWORD versize;
2699 UINT sz;
2700 LPVOID version;
2701 static const WCHAR name[] =
2702 {'\\',0};
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)
2725 file->State = 2;
2726 FIXME("cost should be diff in size\n");
2727 comp->Cost += file->FileSize;
2729 else
2730 file->State = 3;
2731 HeapFree(GetProcessHeap(),0,version);
2733 else
2734 file->State = 3;
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);
2749 return rc;
2752 while (1)
2754 LPCWSTR Feature;
2755 MSIRECORD * row = 0;
2756 int feature_index;
2758 rc = MSI_ViewFetch(view,&row);
2760 if (rc != ERROR_SUCCESS)
2762 rc = ERROR_SUCCESS;
2763 break;
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));
2771 else
2773 LPCWSTR Condition;
2774 Condition = MSI_RecordGetString(row,3);
2776 if (MSI_EvaluateConditionW(package,Condition) ==
2777 MSICONDITION_TRUE)
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);
2810 if (!level)
2811 MSI_SetPropertyW(package,szlevel, szOne);
2812 else
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,
2824 WCHAR* source)
2826 UINT rc;
2827 USHORT* data;
2828 UINT size;
2829 DWORD write;
2830 HANDLE the_file;
2831 WCHAR tmp[MAX_PATH];
2833 rc = read_raw_stream_data(package->db,stream_name,&data,&size);
2834 if (rc != ERROR_SUCCESS)
2835 return rc;
2837 write = MAX_PATH;
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;
2851 goto end;
2854 WriteFile(the_file,data,size,&write,NULL);
2855 CloseHandle(the_file);
2856 TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
2857 end:
2858 HeapFree(GetProcessHeap(),0,data);
2859 return rc;
2863 /* Support functions for FDI functions */
2864 typedef struct
2866 MSIPACKAGE* package;
2867 LPCSTR cab_path;
2868 LPCSTR file_name;
2869 } CabData;
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)
2883 DWORD dwAccess = 0;
2884 DWORD dwShareMode = 0;
2885 DWORD dwCreateDisposition = OPEN_EXISTING;
2886 switch (oflag & _O_ACCMODE)
2888 case _O_RDONLY:
2889 dwAccess = GENERIC_READ;
2890 dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
2891 break;
2892 case _O_WRONLY:
2893 dwAccess = GENERIC_WRITE;
2894 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2895 break;
2896 case _O_RDWR:
2897 dwAccess = GENERIC_READ | GENERIC_WRITE;
2898 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2899 break;
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)
2911 DWORD dwRead;
2912 if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
2913 return dwRead;
2914 return 0;
2917 static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
2919 DWORD dwWritten;
2920 if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
2921 return dwWritten;
2922 return 0;
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 */
2939 switch (fdint)
2941 case fdintCOPY_FILE:
2943 CabData *data = (CabData*) pfdin->pv;
2944 ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
2945 char *file;
2947 LPWSTR trackname;
2948 LPWSTR trackpath;
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))
2953 return 0;
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:
2980 FILETIME ft;
2981 FILETIME ftLocal;
2982 if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
2983 return -1;
2984 if (!LocalFileTimeToFileTime(&ft, &ftLocal))
2985 return -1;
2986 if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
2987 return -1;
2989 cabinet_close(pfdin->hf);
2990 return 1;
2992 default:
2993 return 0;
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)
3005 HFDI hfdi;
3006 ERF erf;
3007 BOOL ret;
3008 char *cabinet;
3009 char *cab_path;
3010 char *file_name;
3011 CabData data;
3013 TRACE("Extracting %s (%s) to %s\n",debugstr_w(source),
3014 debugstr_w(file), debugstr_w(path));
3016 hfdi = FDICreate(cabinet_alloc,
3017 cabinet_free,
3018 cabinet_open,
3019 cabinet_read,
3020 cabinet_write,
3021 cabinet_close,
3022 cabinet_seek,
3024 &erf);
3025 if (!hfdi)
3027 ERR("FDICreate failed\n");
3028 return FALSE;
3031 if (!(cabinet = strdupWtoA( source )))
3033 FDIDestroy(hfdi);
3034 return FALSE;
3036 if (!(cab_path = strdupWtoA( path )))
3038 FDIDestroy(hfdi);
3039 HeapFree(GetProcessHeap(), 0, cabinet);
3040 return FALSE;
3043 data.package = package;
3044 data.cab_path = cab_path;
3045 if (file)
3046 file_name = strdupWtoA(file);
3047 else
3048 file_name = NULL;
3049 data.file_name = file_name;
3051 ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
3053 if (!ret)
3054 ERR("FDICopy failed\n");
3056 FDIDestroy(hfdi);
3058 HeapFree(GetProcessHeap(), 0, cabinet);
3059 HeapFree(GetProcessHeap(), 0, cab_path);
3060 HeapFree(GetProcessHeap(), 0, file_name);
3062 return ret;
3065 static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path,
3066 MSIFILE* file)
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};
3077 LPCWSTR cab;
3078 DWORD sz;
3079 INT seq;
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);
3096 if (!row)
3097 return ERROR_FUNCTION_FAILED;
3099 seq = MSI_RecordGetInteger(row,2);
3100 last_sequence = seq;
3102 cab = MSI_RecordGetString(row,4);
3103 if (cab)
3105 TRACE("Source is CAB %s\n",debugstr_w(cab));
3106 /* the stream does not contain the # character */
3107 if (cab[0]=='#')
3109 writeout_cabinet_stream(package,&cab[1],source);
3110 strcpyW(path,source);
3111 *(strrchrW(path,'\\')+1)=0;
3113 else
3115 sz = MAX_PATH;
3116 if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
3118 ERR("No Source dir defined \n");
3119 rc = ERROR_FUNCTION_FAILED;
3121 else
3123 strcpyW(path,source);
3124 strcatW(source,cab);
3125 /* extract the cab file into a folder in the temp folder */
3126 sz = MAX_PATH;
3127 if (MSI_GetPropertyW(package, cszTempFolder,path, &sz)
3128 != ERROR_SUCCESS)
3129 GetTempPathW(MAX_PATH,path);
3132 rc = !extract_a_cabinet_file(package, source,path,NULL);
3134 else
3136 sz = MAX_PATH;
3137 MSI_GetPropertyW(package,cszSourceDir,source,&sz);
3138 strcpyW(path,source);
3140 msiobj_release(&row->hdr);
3141 return rc;
3144 inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
3146 UINT rc = ERROR_SUCCESS;
3147 MSIFOLDER *folder;
3148 LPWSTR install_path;
3150 install_path = resolve_folder(package, package->components[component].Directory,
3151 FALSE, FALSE, &folder);
3152 if (!install_path)
3153 return ERROR_FUNCTION_FAILED;
3155 /* create the path */
3156 if (folder->State == 0)
3158 create_full_pathW(install_path);
3159 folder->State = 2;
3161 HeapFree(GetProcessHeap(), 0, install_path);
3163 return rc;
3166 static UINT ACTION_InstallFiles(MSIPACKAGE *package)
3168 UINT rc = ERROR_SUCCESS;
3169 DWORD index;
3170 MSIRECORD * uirow;
3171 WCHAR uipath[MAX_PATH];
3173 if (!package)
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];
3182 MSIFILE *file;
3184 file = &package->files[index];
3186 if (file->Temporary)
3187 continue;
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));
3197 continue;
3200 if ((file->State == 1) || (file->State == 2))
3202 LPWSTR p;
3203 MSICOMPONENT* comp = NULL;
3205 TRACE("Installing %s\n",debugstr_w(file->File));
3206 rc = ready_media_for_file(package, path_to_source, file);
3208 * WARNING!
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;
3217 break;
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);
3239 else
3240 file->SourcePath = build_directory_name(2, path_to_source,
3241 file->File);
3244 TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
3245 debugstr_w(file->TargetPath));
3247 /* the UI chunk */
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);
3261 else
3262 rc = MoveFileW(file->SourcePath, file->TargetPath);
3264 if (!rc)
3266 rc = GetLastError();
3267 ERR("Unable to move/copy file (%s -> %s) (error %d)\n",
3268 debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
3269 rc);
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);
3278 rc = 0;
3280 else if (rc == ERROR_FILE_NOT_FOUND)
3282 ERR("Source File Not Found! Continuing\n");
3283 rc = 0;
3285 else if (file->Attributes & msidbFileAttributesVital)
3287 ERR("Ignoring Error and continuing (nonvital file)...\n");
3288 rc = 0;
3291 else
3293 file->State = 4;
3294 rc = ERROR_SUCCESS;
3299 return rc;
3302 inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
3303 LPWSTR* file_source)
3305 DWORD index;
3307 if (!package)
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;
3319 else
3320 return ERROR_FILE_NOT_FOUND;
3324 return ERROR_FUNCTION_FAILED;
3327 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
3329 UINT rc;
3330 MSIQUERY * view;
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};
3336 if (!package)
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);
3348 return rc;
3351 while (1)
3353 WCHAR *file_source = NULL;
3354 WCHAR dest_name[0x100];
3355 LPWSTR dest_path, dest;
3356 LPCWSTR file_key, component;
3357 INT component_index;
3359 DWORD sz;
3361 rc = MSI_ViewFetch(view,&row);
3362 if (rc != ERROR_SUCCESS)
3364 rc = ERROR_SUCCESS;
3365 break;
3368 component = MSI_RecordGetString(row,2);
3369 if (!component)
3371 ERR("Unable to get component\n");
3372 msiobj_release(&row->hdr);
3373 break;
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);
3388 continue;
3391 package->components[component_index].Action = INSTALLSTATE_LOCAL;
3393 file_key = MSI_RecordGetString(row,3);
3394 if (!file_key)
3396 ERR("Unable to get file key\n");
3397 msiobj_release(&row->hdr);
3398 break;
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);
3408 continue;
3411 if (MSI_RecordIsNull(row,4))
3413 strcpyW(dest_name,strrchrW(file_source,'\\')+1);
3415 else
3417 sz=0x100;
3418 MSI_RecordGetStringW(row,4,dest_name,&sz);
3419 reduce_to_longfilename(dest_name);
3422 if (MSI_RecordIsNull(row,5))
3424 LPWSTR p;
3425 dest_path = strdupW(file_source);
3426 p = strrchrW(dest_path,'\\');
3427 if (p)
3428 *p=0;
3430 else
3432 LPCWSTR destkey;
3433 destkey = MSI_RecordGetString(row,5);
3434 dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
3435 if (!dest_path)
3437 ERR("Unable to get destination folder\n");
3438 msiobj_release(&row->hdr);
3439 HeapFree(GetProcessHeap(),0,file_source);
3440 break;
3444 dest = build_directory_name(2, dest_path, dest_name);
3446 TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
3447 debugstr_w(dest));
3449 if (strcmpW(file_source,dest))
3450 rc = !CopyFileW(file_source,dest,TRUE);
3451 else
3452 rc = ERROR_SUCCESS;
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);
3466 return rc;
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,
3473 DWORD *size)
3475 LPSTR data = NULL;
3476 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
3478 if (value[1]=='x')
3480 LPWSTR ptr;
3481 CHAR byte[5];
3482 LPWSTR deformated = NULL;
3483 int count;
3485 deformat_string(package, &value[2], &deformated);
3487 /* binary value type */
3488 ptr = deformated;
3489 *type = REG_BINARY;
3490 if (strlenW(ptr)%2)
3491 *size = (strlenW(ptr)/2)+1;
3492 else
3493 *size = strlenW(ptr)/2;
3495 data = HeapAlloc(GetProcessHeap(),0,*size);
3497 byte[0] = '0';
3498 byte[1] = 'x';
3499 byte[4] = 0;
3500 count = 0;
3501 /* if uneven pad with a zero in front */
3502 if (strlenW(ptr)%2)
3504 byte[2]= '0';
3505 byte[3]= *ptr;
3506 ptr++;
3507 data[count] = (BYTE)strtol(byte,NULL,0);
3508 count ++;
3509 TRACE("Uneven byte count\n");
3511 while (*ptr)
3513 byte[2]= *ptr;
3514 ptr++;
3515 byte[3]= *ptr;
3516 ptr++;
3517 data[count] = (BYTE)strtol(byte,NULL,0);
3518 count ++;
3520 HeapFree(GetProcessHeap(),0,deformated);
3522 TRACE("Data %li bytes(%i)\n",*size,count);
3524 else
3526 LPWSTR deformated;
3527 LPWSTR p;
3528 DWORD d = 0;
3529 deformat_string(package, &value[1], &deformated);
3531 *type=REG_DWORD;
3532 *size = sizeof(DWORD);
3533 data = HeapAlloc(GetProcessHeap(),0,*size);
3534 p = deformated;
3535 if (*p == '-')
3536 p++;
3537 while (*p)
3539 if ( (*p < '0') || (*p > '9') )
3540 break;
3541 d *= 10;
3542 d += (*p - '0');
3543 p++;
3545 if (deformated[0] == '-')
3546 d = -d;
3547 *(LPDWORD)data = d;
3548 TRACE("DWORD %li\n",*(LPDWORD)data);
3550 HeapFree(GetProcessHeap(),0,deformated);
3553 else
3555 static const WCHAR szMulti[] = {'[','~',']',0};
3556 WCHAR *ptr;
3557 *type=REG_SZ;
3559 if (value[0]=='#')
3561 if (value[1]=='%')
3563 ptr = &value[2];
3564 *type=REG_EXPAND_SZ;
3566 else
3567 ptr = &value[1];
3569 else
3570 ptr=value;
3572 if (strstrW(value,szMulti))
3573 *type = REG_MULTI_SZ;
3575 *size = deformat_string(package, ptr,(LPWSTR*)&data);
3577 return data;
3580 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
3582 UINT rc;
3583 MSIQUERY * view;
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 };
3589 if (!package)
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);
3601 return rc;
3604 /* increment progress bar each time action data is sent */
3605 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
3607 while (1)
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;
3623 DWORD type,size;
3624 LPWSTR value, key, name, component, deformated;
3625 LPCWSTR szRoot;
3626 INT component_index;
3627 MSIRECORD * uirow;
3628 LPWSTR uikey;
3629 INT root;
3630 BOOL check_first = FALSE;
3632 rc = MSI_ViewFetch(view,&row);
3633 if (rc != ERROR_SUCCESS)
3635 rc = ERROR_SUCCESS;
3636 break;
3638 ui_progress(package,2,0,0,0);
3640 value = NULL;
3641 key = NULL;
3642 uikey = NULL;
3643 name = NULL;
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;
3657 goto next;
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);
3669 goto next;
3671 else if ((name[0]=='+' && name[1] == 0) ||
3672 (name[0] == '*' && name[1] == 0))
3674 HeapFree(GetProcessHeap(),0,name);
3675 name = NULL;
3676 check_first = TRUE;
3680 root = MSI_RecordGetInteger(row,2);
3681 key = load_dynamic_stringW(row, 3);
3684 /* get the root key */
3685 switch (root)
3687 case 0: root_key = HKEY_CLASSES_ROOT;
3688 szRoot = szHCR;
3689 break;
3690 case 1: root_key = HKEY_CURRENT_USER;
3691 szRoot = szHCU;
3692 break;
3693 case 2: root_key = HKEY_LOCAL_MACHINE;
3694 szRoot = szHLM;
3695 break;
3696 case 3: root_key = HKEY_USERS;
3697 szRoot = szHU;
3698 break;
3699 default:
3700 ERR("Unknown root %i\n",root);
3701 root_key=NULL;
3702 szRoot = NULL;
3703 break;
3705 if (!root_key)
3707 msiobj_release(&row->hdr);
3708 goto next;
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);
3722 goto next;
3724 HeapFree(GetProcessHeap(),0,deformated);
3726 value = load_dynamic_stringW(row,5);
3727 if (value)
3728 value_data = parse_value(package, value, &type, &size);
3729 else
3731 static const WCHAR szEmpty[] = {0};
3732 value_data = (LPSTR)strdupW(szEmpty);
3733 size = 0;
3734 type = REG_SZ;
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);
3743 if (!check_first)
3745 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
3746 debugstr_w(uikey));
3747 RegSetValueExW(hkey, deformated, 0, type, value_data, size);
3749 else
3751 DWORD sz = 0;
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));
3758 else
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);
3770 if (type == REG_SZ)
3771 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
3772 else
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);
3783 RegCloseKey(hkey);
3784 next:
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);
3792 return rc;
3795 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3797 package->script->CurrentlyScripting = TRUE;
3799 return ERROR_SUCCESS;
3803 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3805 DWORD progress = 0;
3806 DWORD total = 0;
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};
3810 UINT rc;
3811 MSIQUERY * view;
3812 MSIRECORD * row = 0;
3813 int i;
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);
3826 return rc;
3828 while (1)
3830 rc = MSI_ViewFetch(view,&row);
3831 if (rc != ERROR_SUCCESS)
3833 rc = ERROR_SUCCESS;
3834 break;
3836 progress +=1;
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)
3862 UINT rc;
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);
3882 return rc;
3885 rc = ERROR_SUCCESS;
3886 while (rc == ERROR_SUCCESS)
3888 LPWSTR cond = NULL;
3889 LPWSTR message = NULL;
3891 rc = MSI_ViewFetch(view,&row);
3892 if (rc != ERROR_SUCCESS)
3894 rc = ERROR_SUCCESS;
3895 break;
3898 cond = load_dynamic_stringW(row,1);
3900 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
3902 LPWSTR deformated;
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);
3915 return rc;
3918 static LPWSTR resolve_keypath( MSIPACKAGE* package, INT
3919 component_index)
3921 MSICOMPONENT* cmp = &package->components[component_index];
3923 if (cmp->KeyPath[0]==0)
3925 LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
3926 return p;
3928 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3930 MSIRECORD * row = 0;
3931 UINT root,len;
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);
3943 if (!row)
3944 return NULL;
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);
3960 else
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);
3969 return buffer;
3971 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3973 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3974 return NULL;
3976 else
3978 int j;
3979 j = get_loaded_file(package,cmp->KeyPath);
3981 if (j>=0)
3983 LPWSTR p = strdupW(package->files[j].TargetPath);
3984 return p;
3987 return NULL;
3990 static HKEY openSharedDLLsKey()
3992 HKEY hkey=0;
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);
4001 return hkey;
4004 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
4006 HKEY hkey;
4007 DWORD count=0;
4008 DWORD type;
4009 DWORD sz = sizeof(count);
4010 DWORD rc;
4012 hkey = openSharedDLLsKey();
4013 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
4014 if (rc != ERROR_SUCCESS)
4015 count = 0;
4016 RegCloseKey(hkey);
4017 return count;
4020 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
4022 HKEY hkey;
4024 hkey = openSharedDLLsKey();
4025 if (count > 0)
4026 RegSetValueExW(hkey,path,0,REG_DWORD,
4027 (LPBYTE)&count,sizeof(count));
4028 else
4029 RegDeleteValueW(hkey,path);
4030 RegCloseKey(hkey);
4031 return count;
4035 * Return TRUE if the count should be written out and FALSE if not
4037 static void ACTION_RefCountComponent( MSIPACKAGE* package, UINT index)
4039 INT count = 0;
4040 BOOL write = FALSE;
4041 INT j;
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)
4049 write = FALSE;
4050 else
4052 count = ACTION_GetSharedDLLsCount(package->components[index].
4053 FullKeypath);
4054 write = (count > 0);
4056 if (package->components[index].Attributes &
4057 msidbComponentAttributesSharedDllRefCount)
4058 write = TRUE;
4061 /* increment counts */
4062 for (j = 0; j < package->loaded_features; j++)
4064 int i;
4066 if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_LOCAL))
4067 continue;
4069 for (i = 0; i < package->features[j].ComponentCount; i++)
4071 if (package->features[j].Components[i] == index)
4072 count++;
4075 /* decrement counts */
4076 for (j = 0; j < package->loaded_features; j++)
4078 int i;
4079 if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_ABSENT))
4080 continue;
4082 for (i = 0; i < package->features[j].ComponentCount; i++)
4084 if (package->features[j].Components[i] == index)
4085 count--;
4089 /* ref count all the files in the component */
4090 if (write)
4091 for (j = 0; j < package->loaded_files; j++)
4093 if (package->files[j].Temporary)
4094 continue;
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)
4102 count ++;
4104 package->components[index].RefCount = count;
4106 if (write)
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)
4120 LPWSTR productcode;
4121 WCHAR squished_pc[GUID_SIZE];
4122 WCHAR squished_cc[GUID_SIZE];
4123 UINT rc;
4124 DWORD i;
4125 HKEY hkey=0,hkey2=0;
4127 if (!package)
4128 return ERROR_INVALID_HANDLE;
4130 /* writes the Component and Features values to the registry */
4131 productcode = load_dynamic_property(package,szProductCode,&rc);
4132 if (!productcode)
4133 return rc;
4135 rc = MSIREG_OpenComponents(&hkey);
4136 if (rc != ERROR_SUCCESS)
4137 goto end;
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;
4147 MSIRECORD * uirow;
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)
4171 continue;
4173 if (keypath)
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,
4187 (LPVOID)keypath,
4188 (strlenW(keypath)+1)*sizeof(WCHAR));
4191 RegCloseKey(hkey2);
4193 /* UI stuff */
4194 uirow = MSI_CreateRecord(3);
4195 MSI_RecordSetStringW(uirow,1,productcode);
4196 MSI_RecordSetStringW(uirow,2,package->components[i].
4197 ComponentId);
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))
4206 DWORD res;
4208 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
4209 if (rc != ERROR_SUCCESS)
4210 continue;
4212 RegDeleteValueW(hkey2,squished_pc);
4214 /* if the key is empty delete it */
4215 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
4216 RegCloseKey(hkey2);
4217 if (res == ERROR_NO_MORE_ITEMS)
4218 RegDeleteKeyW(hkey,squished_cc);
4220 /* UI stuff */
4221 uirow = MSI_CreateRecord(2);
4222 MSI_RecordSetStringW(uirow,1,productcode);
4223 MSI_RecordSetStringW(uirow,2,package->components[i].
4224 ComponentId);
4225 ui_actiondata(package,szProcessComponents,uirow);
4226 msiobj_release( &uirow->hdr );
4230 end:
4231 HeapFree(GetProcessHeap(), 0, productcode);
4232 RegCloseKey(hkey);
4233 return rc;
4236 typedef struct {
4237 CLSID clsid;
4238 LPWSTR source;
4240 LPWSTR path;
4241 ITypeLib *ptLib;
4242 } typelib_struct;
4244 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
4245 LPWSTR lpszName, LONG_PTR lParam)
4247 TLIBATTR *attr;
4248 typelib_struct *tl_struct = (typelib_struct*) lParam;
4249 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
4250 int sz;
4251 HRESULT res;
4253 if (!IS_INTRESOURCE(lpszName))
4255 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
4256 return TRUE;
4259 sz = strlenW(tl_struct->source)+4;
4260 sz *= sizeof(WCHAR);
4262 if ((INT)lpszName == 1)
4263 tl_struct->path = strdupW(tl_struct->source);
4264 else
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;
4277 return TRUE;
4280 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
4281 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
4283 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
4284 return FALSE;
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);
4293 return TRUE;
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
4302 * that component".
4304 UINT rc;
4305 MSIQUERY * view;
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};
4311 if (!package)
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);
4323 return rc;
4326 while (1)
4328 WCHAR component[0x100];
4329 DWORD sz;
4330 INT index;
4331 LPWSTR guid;
4332 typelib_struct tl_struct;
4333 HMODULE module;
4334 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
4336 rc = MSI_ViewFetch(view,&row);
4337 if (rc != ERROR_SUCCESS)
4339 rc = ERROR_SUCCESS;
4340 break;
4343 sz = 0x100;
4344 MSI_RecordGetStringW(row,3,component,&sz);
4346 index = get_loaded_component(package,component);
4347 if (index < 0)
4349 msiobj_release(&row->hdr);
4350 continue;
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;
4362 continue;
4365 package->components[index].Action = INSTALLSTATE_LOCAL;
4367 index = get_loaded_file(package,package->components[index].KeyPath);
4369 if (index < 0)
4371 msiobj_release(&row->hdr);
4372 continue;
4375 guid = load_dynamic_stringW(row,1);
4376 module = LoadLibraryExW(package->files[index].TargetPath, NULL,
4377 LOAD_LIBRARY_AS_DATAFILE);
4378 if (module != NULL)
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)
4389 LPWSTR help;
4390 WCHAR helpid[0x100];
4391 HRESULT res;
4393 sz = 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));
4403 else
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);
4413 else
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);
4420 else
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);
4427 return rc;
4430 static INT load_appid(MSIPACKAGE* package, MSIRECORD *row)
4432 DWORD index = package->loaded_appids;
4433 DWORD sz;
4434 LPWSTR buffer;
4436 /* fill in the data */
4438 package->loaded_appids++;
4439 if (package->loaded_appids == 1)
4440 package->appids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIAPPID));
4441 else
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);
4462 return index;
4465 static INT load_given_appid(MSIPACKAGE *package, LPCWSTR appid)
4467 INT rc;
4468 MSIRECORD *row;
4469 INT i;
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};
4475 if (!appid)
4476 return -1;
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);
4483 return i;
4486 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, appid);
4487 if (!row)
4488 return -1;
4490 rc = load_appid(package, row);
4491 msiobj_release(&row->hdr);
4493 return rc;
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;
4502 LPWSTR buffer;
4504 /* fill in the data */
4506 package->loaded_progids++;
4507 if (package->loaded_progids == 1)
4508 package->progids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIPROGID));
4509 else
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);
4536 LPWSTR FilePath;
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)*
4543 sizeof(WCHAR));
4545 sprintfW(package->progids[index].IconPath,fmt,FilePath,icon_index);
4547 HeapFree(GetProcessHeap(),0,FilePath);
4548 HeapFree(GetProcessHeap(),0,FileName);
4550 else
4552 buffer = load_dynamic_stringW(row,5);
4553 if (buffer)
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;
4575 return index;
4578 static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid)
4580 INT rc;
4581 MSIRECORD *row;
4582 INT i;
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};
4588 if (!progid)
4589 return -1;
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);
4596 return i;
4599 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, progid);
4600 if(!row)
4601 return -1;
4603 rc = load_progid(package, row);
4604 msiobj_release(&row->hdr);
4606 return rc;
4609 static INT load_class(MSIPACKAGE* package, MSIRECORD *row)
4611 DWORD index = package->loaded_classes;
4612 DWORD sz,i;
4613 LPWSTR buffer;
4615 /* fill in the data */
4617 package->loaded_classes++;
4618 if (package->loaded_classes== 1)
4619 package->classes = HeapAlloc(GetProcessHeap(),0,sizeof(MSICLASS));
4620 else
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,
4633 buffer);
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);
4643 if (buffer)
4644 package->classes[index].AppIDIndex =
4645 load_given_appid(package, buffer);
4646 else
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);
4657 LPWSTR FilePath;
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)*
4664 sizeof(WCHAR));
4666 sprintfW(package->classes[index].IconPath,fmt,FilePath,icon_index);
4668 HeapFree(GetProcessHeap(),0,FilePath);
4669 HeapFree(GetProcessHeap(),0,FileName);
4671 else
4673 buffer = load_dynamic_stringW(row,8);
4674 if (buffer)
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};
4687 switch(i)
4689 case 1:
4690 package->classes[index].DefInprocHandler = strdupW(ole2);
4691 break;
4692 case 2:
4693 package->classes[index].DefInprocHandler32 = strdupW(ole32);
4694 break;
4695 case 3:
4696 package->classes[index].DefInprocHandler = strdupW(ole2);
4697 package->classes[index].DefInprocHandler32 = strdupW(ole32);
4698 break;
4701 else
4703 package->classes[index].DefInprocHandler32 = load_dynamic_stringW(
4704 row, 10);
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);
4718 return index;
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)
4729 INT rc;
4730 MSIRECORD *row;
4731 INT i;
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};
4738 if (!classid)
4739 return -1;
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);
4746 return i;
4749 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, classid);
4750 if (!row)
4751 return -1;
4753 rc = load_class(package, row);
4754 msiobj_release(&row->hdr);
4756 return rc;
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;
4764 DWORD sz;
4765 LPWSTR buffer;
4767 /* fill in the data */
4769 package->loaded_mimes++;
4770 if (package->loaded_mimes== 1)
4771 package->mimes= HeapAlloc(GetProcessHeap(),0,sizeof(MSIMIME));
4772 else
4773 package->mimes= HeapReAlloc(GetProcessHeap(),0,
4774 package->mimes, package->loaded_mimes*
4775 sizeof(MSIMIME));
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,
4784 buffer);
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);
4792 return index;
4795 static INT load_given_mime(MSIPACKAGE *package, LPCWSTR mime)
4797 INT rc;
4798 MSIRECORD *row;
4799 INT i;
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};
4806 if (!mime)
4807 return -1;
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);
4814 return i;
4817 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, mime);
4818 if (!row)
4819 return -1;
4821 rc = load_mime(package, row);
4822 msiobj_release(&row->hdr);
4824 return rc;
4827 static INT load_extension(MSIPACKAGE* package, MSIRECORD *row)
4829 DWORD index = package->loaded_extensions;
4830 DWORD sz;
4831 LPWSTR buffer;
4833 /* fill in the data */
4835 package->loaded_extensions++;
4836 if (package->loaded_extensions == 1)
4837 package->extensions = HeapAlloc(GetProcessHeap(),0,sizeof(MSIEXTENSION));
4838 else
4839 package->extensions = HeapReAlloc(GetProcessHeap(),0,
4840 package->extensions, package->loaded_extensions*
4841 sizeof(MSIEXTENSION));
4843 memset(&package->extensions[index],0,sizeof(MSIEXTENSION));
4845 sz = 256;
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);
4868 return index;
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)
4877 INT rc;
4878 MSIRECORD *row;
4879 INT i;
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};
4887 if (!extension)
4888 return -1;
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),
4896 return i;
4899 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, extension);
4900 if (!row)
4901 return -1;
4903 rc = load_extension(package, row);
4904 msiobj_release(&row->hdr);
4906 return rc;
4909 static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
4911 MSIPACKAGE* package = (MSIPACKAGE*)param;
4912 DWORD index = package->loaded_verbs;
4913 LPWSTR buffer;
4915 /* fill in the data */
4917 package->loaded_verbs++;
4918 if (package->loaded_verbs == 1)
4919 package->verbs = HeapAlloc(GetProcessHeap(),0,sizeof(MSIVERB));
4920 else
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].
4948 ExtensionIndex];
4949 int count = extension->VerbCount;
4951 if (count >= 99)
4952 FIXME("Exceeding max verb count! Increase that limit!!!\n");
4953 else
4955 extension->VerbCount++;
4956 extension->Verbs[count] = index;
4960 return ERROR_SUCCESS;
4963 static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param)
4965 LPWSTR clsid;
4966 LPWSTR context;
4967 LPWSTR buffer;
4968 INT component_index;
4969 MSIPACKAGE* package =(MSIPACKAGE*)param;
4970 INT i;
4971 BOOL match = FALSE;
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))
4981 continue;
4982 if (strcmpW(context,package->classes[i].Context))
4983 continue;
4984 if (component_index == package->classes[i].ComponentIndex)
4986 match = TRUE;
4987 break;
4991 HeapFree(GetProcessHeap(),0,buffer);
4992 HeapFree(GetProcessHeap(),0,clsid);
4993 HeapFree(GetProcessHeap(),0,context);
4995 if (!match)
4996 load_class(package, rec);
4998 return ERROR_SUCCESS;
5001 static VOID load_all_classes(MSIPACKAGE *package)
5003 UINT rc = ERROR_SUCCESS;
5004 MSIQUERY *view;
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)
5012 return;
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)
5020 LPWSTR buffer;
5021 LPWSTR extension;
5022 INT component_index;
5023 MSIPACKAGE* package =(MSIPACKAGE*)param;
5024 BOOL match = FALSE;
5025 INT i;
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))
5034 continue;
5035 if (component_index == package->extensions[i].ComponentIndex)
5037 match = TRUE;
5038 break;
5042 HeapFree(GetProcessHeap(),0,buffer);
5043 HeapFree(GetProcessHeap(),0,extension);
5045 if (!match)
5046 load_extension(package, rec);
5048 return ERROR_SUCCESS;
5051 static VOID load_all_extensions(MSIPACKAGE *package)
5053 UINT rc = ERROR_SUCCESS;
5054 MSIQUERY *view;
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)
5062 return;
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)
5070 LPWSTR buffer;
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;
5082 MSIQUERY *view;
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)
5090 return;
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;
5099 MSIQUERY *view;
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)
5107 return;
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)
5115 LPWSTR buffer;
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;
5127 MSIQUERY *view;
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)
5137 return;
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)
5150 return;
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)
5162 MSIPROGID* progid;
5163 int i;
5165 if (index < 0 || index >= package->loaded_progids)
5166 return;
5168 progid = &package->progids[index];
5170 if (progid->InstallMe == TRUE)
5171 return;
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)
5183 MSIMIME* mime;
5185 if (index < 0 || index >= package->loaded_mimes)
5186 return;
5188 mime = &package->mimes[index];
5190 if (mime->InstallMe == TRUE)
5191 return;
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 };
5199 HKEY hkey2,hkey3;
5201 if (!package)
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)
5211 UINT size;
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) *
5217 sizeof(WCHAR);
5219 RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,
5220 (LPVOID)package->appids[appidIndex].RemoteServerName,
5221 size);
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};
5228 UINT size;
5229 size = (strlenW(package->appids[appidIndex].LocalServer)+1) *
5230 sizeof(WCHAR);
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};
5241 UINT size;
5242 size = (strlenW(package->appids[appidIndex].ServiceParameters)+1) *
5243 sizeof(WCHAR);
5244 RegSetValueExW(hkey3,szService,0,REG_SZ,
5245 (LPVOID)package->appids[appidIndex].ServiceParameters,
5246 size);
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};
5253 UINT size;
5254 size = (strlenW(package->appids[appidIndex].DllSurrogate)+1) *
5255 sizeof(WCHAR);
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',' ',
5275 'U','s','e','r',0};
5277 RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,sizeof(szUser));
5280 RegCloseKey(hkey3);
5281 RegCloseKey(hkey2);
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
5292 UINT rc;
5293 MSIRECORD *uirow;
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;
5303 int i;
5305 if (!package)
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++)
5320 INT index,f_index;
5321 DWORD size, sz;
5322 LPWSTR argument;
5324 if (package->classes[i].ComponentIndex < 0)
5326 continue;
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));
5345 continue;
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)
5371 sz = 0;
5372 sz = GetShortPathNameW(package->files[index].TargetPath, NULL, 0);
5373 if (sz == 0)
5375 ERR("Unable to find short path for CLSID COM Server\n");
5376 argument = NULL;
5378 else
5380 size = sz * sizeof(WCHAR);
5382 if (package->classes[i].Argument)
5384 size += strlenW(package->classes[i].Argument) *
5385 sizeof(WCHAR);
5386 size += sizeof(WCHAR);
5389 argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
5390 GetShortPathNameW(package->files[index].TargetPath, argument,
5391 sz);
5393 if (package->classes[i].Argument)
5395 strcatW(argument,szSpace);
5396 strcatW(argument,package->classes[i].Argument);
5400 else
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);
5420 if (argument)
5422 RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
5423 HeapFree(GetProcessHeap(),0,argument);
5426 RegCloseKey(hkey3);
5428 if (package->classes[i].ProgIDIndex >= 0 ||
5429 package->classes[i].ProgIDText)
5431 LPCWSTR progid;
5433 if (package->classes[i].ProgIDIndex >= 0)
5434 progid = package->progids[
5435 package->classes[i].ProgIDIndex].ProgID;
5436 else
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));
5442 RegCloseKey(hkey3);
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].
5450 ProgID);
5451 RegCreateKeyW(hkey2,szVIProgID,&hkey3);
5452 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)viprogid,
5453 (strlenW(viprogid)+1) *sizeof(WCHAR));
5454 RegCloseKey(hkey3);
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)
5464 *sizeof(WCHAR));
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) *
5480 sizeof(WCHAR));
5482 RegCloseKey(hkey3);
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) *
5491 sizeof(WCHAR);
5492 RegCreateKeyW(hkey2,szInproc,&hkey3);
5493 RegSetValueExW(hkey3,NULL,0,REG_SZ,
5494 (LPVOID)package->classes[i].DefInprocHandler, size);
5495 RegCloseKey(hkey3);
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) *
5504 sizeof(WCHAR);
5506 RegCreateKeyW(hkey2,szInproc32,&hkey3);
5507 RegSetValueExW(hkey3,NULL,0,REG_SZ,
5508 (LPVOID)package->classes[i].DefInprocHandler32,size);
5509 RegCloseKey(hkey3);
5512 RegCloseKey(hkey2);
5514 /* if there is a FileTypeMask, register the FileType */
5515 if (package->classes[i].FileTypeMask)
5517 LPWSTR ptr, ptr2;
5518 LPWSTR keyname;
5519 INT index = 0;
5520 ptr = package->classes[i].FileTypeMask;
5521 while (ptr && *ptr)
5523 ptr2 = strchrW(ptr,';');
5524 if (ptr2)
5525 *ptr2 = 0;
5526 keyname = HeapAlloc(GetProcessHeap(),0,(strlenW(szFileType_fmt)+
5527 strlenW(package->classes[i].CLSID) + 4)
5528 * sizeof(WCHAR));
5529 sprintfW(keyname,szFileType_fmt, package->classes[i].CLSID,
5530 index);
5532 RegCreateKeyW(HKEY_CLASSES_ROOT,keyname,&hkey2);
5533 RegSetValueExW(hkey2,NULL,0,REG_SZ, (LPVOID)ptr,
5534 strlenW(ptr)*sizeof(WCHAR));
5535 RegCloseKey(hkey2);
5536 HeapFree(GetProcessHeap(), 0, keyname);
5538 if (ptr2)
5539 ptr = ptr2+1;
5540 else
5541 ptr = NULL;
5543 index ++;
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);
5554 RegCloseKey(hkey);
5555 return rc;
5558 static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid,
5559 LPWSTR clsid)
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};
5564 HKEY hkey,hkey2;
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) *
5573 sizeof(WCHAR));
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)
5582 * sizeof(WCHAR));
5584 if (clsid)
5585 strcpyW(clsid,package->classes[progid->ClassIndex].CLSID);
5587 RegCloseKey(hkey2);
5589 else
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));
5600 RegCloseKey(hkey2);
5602 return ERROR_SUCCESS;
5605 static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid,
5606 LPWSTR clsid)
5608 UINT rc = ERROR_SUCCESS;
5610 if (progid->ParentIndex < 0)
5611 rc = register_progid_base(package, progid, clsid);
5612 else
5614 DWORD disp;
5615 HKEY hkey,hkey2;
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");
5628 RegCloseKey(hkey);
5629 return rc;
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],
5636 clsid);
5638 /* clsid is same as parent */
5639 RegCreateKeyW(hkey,szCLSID,&hkey2);
5640 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
5641 sizeof(WCHAR));
5643 RegCloseKey(hkey2);
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));
5657 RegCloseKey(hkey2);
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) *
5667 sizeof(WCHAR));
5668 RegCloseKey(hkey2);
5671 RegCloseKey(hkey);
5673 return rc;
5676 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
5678 INT i;
5679 MSIRECORD *uirow;
5681 if (!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));
5699 continue;
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,
5717 LPWSTR *FilePath)
5719 LPWSTR ProductCode;
5720 LPWSTR SystemFolder;
5721 LPWSTR dest;
5722 UINT rc;
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);
5731 if (!ProductCode)
5732 return 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)
5750 UINT rc;
5751 MSIQUERY * view;
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};
5756 IShellLinkW *sl;
5757 IPersistFile *pf;
5758 HRESULT res;
5760 if (!package)
5761 return ERROR_INVALID_HANDLE;
5763 res = CoInitialize( NULL );
5764 if (FAILED (res))
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);
5779 return rc;
5782 while (1)
5784 LPWSTR target_file, target_folder;
5785 WCHAR buffer[0x100];
5786 DWORD sz;
5787 DWORD index;
5788 static const WCHAR szlnk[]={'.','l','n','k',0};
5790 rc = MSI_ViewFetch(view,&row);
5791 if (rc != ERROR_SUCCESS)
5793 rc = ERROR_SUCCESS;
5794 break;
5797 sz = 0x100;
5798 MSI_RecordGetStringW(row,4,buffer,&sz);
5800 index = get_loaded_component(package,buffer);
5802 if (index < 0)
5804 msiobj_release(&row->hdr);
5805 continue;
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;
5817 continue;
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 );
5827 if (FAILED(res))
5829 ERR("Is IID_IShellLink\n");
5830 msiobj_release(&row->hdr);
5831 continue;
5834 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
5835 if( FAILED( res ) )
5837 ERR("Is IID_IPersistFile\n");
5838 msiobj_release(&row->hdr);
5839 continue;
5842 sz = 0x100;
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);
5849 sz = 0x100;
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);
5857 sz = 0x100;
5858 MSI_RecordGetStringW(row,5,buffer,&sz);
5859 if (strchrW(buffer,'['))
5861 LPWSTR deformated;
5862 deformat_string(package,buffer,&deformated);
5863 IShellLinkW_SetPath(sl,deformated);
5864 HeapFree(GetProcessHeap(),0,deformated);
5866 else
5868 LPWSTR keypath;
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))
5877 LPWSTR deformated;
5878 sz = 0x100;
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))
5887 LPWSTR deformated;
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))
5898 WCHAR *Path = NULL;
5899 INT index;
5901 sz = 0x100;
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))
5916 LPWSTR Path;
5917 sz = 0x100;
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);
5938 CoUninitialize();
5940 return rc;
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)
5952 UINT rc;
5953 MSIQUERY * view;
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};
5958 DWORD sz;
5959 /* for registry stuff */
5960 LPWSTR productcode;
5961 HKEY hkey=0;
5962 HKEY hukey=0;
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};
5975 DWORD langid;
5976 LPWSTR buffer;
5977 DWORD size;
5978 MSIHANDLE hDb, hSumInfo;
5980 if (!package)
5981 return ERROR_INVALID_HANDLE;
5983 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
5984 if (rc != ERROR_SUCCESS)
5985 goto next;
5987 rc = MSI_ViewExecute(view, 0);
5988 if (rc != ERROR_SUCCESS)
5990 MSI_ViewClose(view);
5991 msiobj_release(&view->hdr);
5992 goto next;
5995 while (1)
5997 HANDLE the_file;
5998 WCHAR *FilePath=NULL;
5999 WCHAR *FileName=NULL;
6000 CHAR buffer[1024];
6002 rc = MSI_ViewFetch(view,&row);
6003 if (rc != ERROR_SUCCESS)
6005 rc = ERROR_SUCCESS;
6006 break;
6009 FileName = load_dynamic_stringW(row,1);
6010 if (!FileName)
6012 ERR("Unable to get FileName\n");
6013 msiobj_release(&row->hdr);
6014 continue;
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);
6031 continue;
6036 DWORD write;
6037 sz = 1024;
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);
6044 break;
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);
6057 next:
6058 /* ok there is a lot more done here but i need to figure out what */
6059 productcode = load_dynamic_property(package,szProductCode,&rc);
6060 if (!productcode)
6061 return rc;
6063 rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE);
6064 if (rc != ERROR_SUCCESS)
6065 goto end;
6067 rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
6068 if (rc != ERROR_SUCCESS)
6069 goto end;
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);
6083 if (buffer)
6085 LPWSTR path;
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];
6099 size = 0x200;
6100 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
6101 guidbuffer, &size);
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,';');
6107 if (ptr) *ptr = 0;
6108 squash_guid(guidbuffer,squashed);
6109 size = strlenW(squashed)*sizeof(WCHAR);
6110 RegSetValueExW(hukey,szPackageCode,0,REG_SZ, (LPSTR)squashed,
6111 size);
6113 else
6115 ERR("Unable to query Revision_Number... \n");
6116 rc = ERROR_SUCCESS;
6118 MsiCloseHandle(hSumInfo);
6120 else
6122 ERR("Unable to open Summary Information\n");
6123 rc = ERROR_SUCCESS;
6126 end:
6128 HeapFree(GetProcessHeap(),0,productcode);
6129 RegCloseKey(hkey);
6130 RegCloseKey(hukey);
6132 return rc;
6135 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
6137 UINT rc;
6138 MSIQUERY * view;
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);
6158 return rc;
6161 while (1)
6163 LPWSTR component,filename,dirproperty,section,key,value,identifier;
6164 LPWSTR deformated_section, deformated_key, deformated_value;
6165 LPWSTR folder, fullname = NULL;
6166 MSIRECORD * uirow;
6167 INT component_index,action;
6169 rc = MSI_ViewFetch(view,&row);
6170 if (rc != ERROR_SUCCESS)
6172 rc = ERROR_SUCCESS;
6173 break;
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;
6189 continue;
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);
6206 if (dirproperty)
6208 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
6209 if (!folder)
6210 folder = load_dynamic_property(package,dirproperty,NULL);
6212 else
6213 folder = load_dynamic_property(package, szWindowsFolder, NULL);
6215 if (!folder)
6217 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
6218 goto cleanup;
6221 fullname = build_directory_name(3, folder, filename, NULL);
6223 if (action == 0)
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)
6233 WCHAR returned[10];
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 );
6258 cleanup:
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);
6274 return rc;
6277 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
6279 UINT rc;
6280 MSIQUERY * view;
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};
6289 STARTUPINFOW si;
6290 PROCESS_INFORMATION info;
6291 BOOL brc;
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);
6307 return rc;
6310 while (1)
6312 LPWSTR filename;
6313 INT index;
6314 DWORD len;
6316 rc = MSI_ViewFetch(view,&row);
6317 if (rc != ERROR_SUCCESS)
6319 rc = ERROR_SUCCESS;
6320 break;
6323 filename = load_dynamic_stringW(row,1);
6324 index = get_loaded_file(package,filename);
6326 if (index < 0)
6328 ERR("Unable to find file id %s\n",debugstr_w(filename));
6329 HeapFree(GetProcessHeap(),0,filename);
6330 msiobj_release(&row->hdr);
6331 continue;
6333 HeapFree(GetProcessHeap(),0,filename);
6335 len = strlenW(ExeStr);
6336 len += strlenW(package->files[index].TargetPath);
6337 len +=2;
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);
6348 if (brc)
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);
6356 return rc;
6359 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
6361 LPWSTR productcode;
6362 UINT rc;
6363 DWORD i;
6364 HKEY hkey=0;
6365 HKEY hukey=0;
6367 if (!package)
6368 return ERROR_INVALID_HANDLE;
6370 productcode = load_dynamic_property(package,szProductCode,&rc);
6371 if (!productcode)
6372 return rc;
6374 rc = MSIREG_OpenFeaturesKey(productcode,&hkey,TRUE);
6375 if (rc != ERROR_SUCCESS)
6376 goto end;
6378 rc = MSIREG_OpenUserFeaturesKey(productcode,&hukey,TRUE);
6379 if (rc != ERROR_SUCCESS)
6380 goto end;
6382 /* here the guids are base 85 encoded */
6383 for (i = 0; i < package->loaded_features; i++)
6385 LPWSTR data = NULL;
6386 GUID clsid;
6387 int j;
6388 INT size;
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))
6394 absent = TRUE;
6396 size = package->features[i].ComponentCount*21;
6397 size +=1;
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));
6403 data[0] = 0;
6404 for (j = 0; j < package->features[i].ComponentCount; j++)
6406 WCHAR buf[21];
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,
6415 &clsid);
6416 encode_base85_guid(&clsid,buf);
6417 TRACE("to %s\n",debugstr_w(buf));
6418 strcatW(data,buf);
6421 if (package->features[i].Feature_Parent[0])
6423 static const WCHAR sep[] = {'\2',0};
6424 strcatW(data,sep);
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,
6430 (LPSTR)data,size);
6431 HeapFree(GetProcessHeap(),0,data);
6433 if (!absent)
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);
6439 else
6441 size = (strlenW(package->features[i].Feature_Parent)+2)*
6442 sizeof(WCHAR);
6443 data = HeapAlloc(GetProcessHeap(),0,size);
6444 data[0] = 0x6;
6445 strcpyW(&data[1],package->features[i].Feature_Parent);
6446 RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,
6447 (LPSTR)data,size);
6448 HeapFree(GetProcessHeap(),0,data);
6452 end:
6453 RegCloseKey(hkey);
6454 RegCloseKey(hukey);
6455 HeapFree(GetProcessHeap(), 0, productcode);
6456 return rc;
6459 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
6461 HKEY hkey=0;
6462 LPWSTR buffer;
6463 LPWSTR productcode;
6464 UINT rc,i;
6465 DWORD size;
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},
6485 {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},
6504 {0},
6507 static const WCHAR installerPathFmt[] = {
6508 '%','s','\\',
6509 'I','n','s','t','a','l','l','e','r','\\',0};
6510 static const WCHAR fmt[] = {
6511 '%','s','\\',
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];
6520 INT num,start;
6522 if (!package)
6523 return ERROR_INVALID_HANDLE;
6525 productcode = load_dynamic_property(package,szProductCode,&rc);
6526 if (!productcode)
6527 return rc;
6529 rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
6530 if (rc != ERROR_SUCCESS)
6531 goto end;
6533 /* dump all the info i can grab */
6534 FIXME("Flesh out more information \n");
6536 i = 0;
6537 while (szPropKeys[i][0]!=0)
6539 buffer = load_dynamic_property(package,szPropKeys[i],&rc);
6540 if (rc != ERROR_SUCCESS)
6541 buffer = szNONE;
6542 size = strlenW(buffer)*sizeof(WCHAR);
6543 RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);
6544 i++;
6547 rc = 0x1;
6548 size = sizeof(rc);
6549 RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPSTR)&rc,size);
6551 /* copy the package locally */
6552 num = GetTickCount() & 0xffff;
6553 if (!num)
6554 num = 1;
6555 start = num;
6556 GetWindowsDirectoryW(windir, sizeof(windir) / sizeof(windir[0]));
6557 snprintfW(packagefile,sizeof(packagefile)/sizeof(packagefile[0]),fmt,
6558 windir,num);
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);
6566 break;
6568 if (GetLastError() != ERROR_FILE_EXISTS &&
6569 GetLastError() != ERROR_SHARING_VIOLATION)
6570 break;
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),
6581 GetLastError());
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);
6587 if (upgrade_code)
6589 HKEY hkey2;
6590 WCHAR squashed[33];
6591 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
6592 squash_guid(productcode,squashed);
6593 RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0);
6594 RegCloseKey(hkey2);
6595 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
6596 squash_guid(productcode,squashed);
6597 RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0);
6598 RegCloseKey(hkey2);
6600 HeapFree(GetProcessHeap(),0,upgrade_code);
6603 end:
6604 HeapFree(GetProcessHeap(),0,productcode);
6605 RegCloseKey(hkey);
6607 return ERROR_SUCCESS;
6610 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
6612 UINT rc;
6614 if (!package)
6615 return ERROR_INVALID_HANDLE;
6617 rc = execute_script(package,INSTALL_SCRIPT);
6619 return rc;
6622 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
6624 UINT rc;
6626 if (!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)
6635 return rc;
6637 /* then handle Commit Actions */
6638 rc = execute_script(package,COMMIT_SCRIPT);
6640 return rc;
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[] = {
6660 '%','s',
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];
6668 HKEY hkey,hukey;
6669 LPWSTR productcode;
6670 WCHAR squished_pc[100];
6671 INT rc;
6672 DWORD size;
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};
6680 if (!package)
6681 return ERROR_INVALID_HANDLE;
6683 productcode = load_dynamic_property(package,szProductCode,&rc);
6684 if (!productcode)
6685 return 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,
6692 squished_pc);
6694 size = strlenW(buffer)*sizeof(WCHAR);
6695 RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
6696 RegCloseKey(hkey);
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);
6705 RegCloseKey(hkey);
6707 rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
6708 if (rc == ERROR_SUCCESS)
6710 HKEY hukey2;
6711 LPWSTR buf;
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,'\\');
6719 if (buf)
6721 buf++;
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;
6746 GUID clsid;
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;
6759 DWORD sz = 0;
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);
6777 if (component)
6778 sz += lstrlenW(component_85);
6780 sz+=3;
6781 sz *= sizeof(WCHAR);
6783 output = HeapAlloc(GetProcessHeap(),0,sz);
6784 memset(output,0,sz);
6786 if (component)
6787 sprintfW(output,fmt2,productid_85,feature,component_85);
6788 else
6789 sprintfW(output,fmt1,productid_85,feature);
6791 HeapFree(GetProcessHeap(),0,productid);
6793 return output;
6796 static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid,
6797 MSICOMPONENT* component, MSIEXTENSION* extension,
6798 MSIVERB* verb, INT* Sequence )
6800 LPWSTR keyname;
6801 HKEY key;
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};
6806 LPWSTR command;
6807 DWORD size;
6808 LPWSTR advertise;
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);
6815 if (verb->Argument)
6816 size += strlenW(verb->Argument);
6817 size += 4;
6819 command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
6820 if (verb->Argument)
6821 sprintfW(command, fmt, component->FullKeypath, verb->Argument);
6822 else
6823 sprintfW(command, fmt2, component->FullKeypath);
6825 RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)command, (strlenW(command)+1)*
6826 sizeof(WCHAR));
6827 HeapFree(GetProcessHeap(),0,command);
6829 advertise = create_component_advertise_string(package, component,
6830 package->features[extension->FeatureIndex].Feature);
6832 size = strlenW(advertise);
6834 if (verb->Argument)
6835 size += strlenW(verb->Argument);
6836 size += 4;
6838 command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
6839 memset(command,0,size*sizeof(WCHAR));
6841 strcpyW(command,advertise);
6842 if (verb->Argument)
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));
6852 RegCloseKey(key);
6853 HeapFree(GetProcessHeap(),0,keyname);
6854 HeapFree(GetProcessHeap(),0,advertise);
6855 HeapFree(GetProcessHeap(),0,command);
6857 if (verb->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));
6863 RegCloseKey(key);
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));
6876 RegCloseKey(key);
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 };
6887 HKEY hkey;
6888 INT i;
6889 MSIRECORD *uirow;
6890 BOOL install_on_demand = TRUE;
6892 if (!package)
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];
6905 INT index,f_index;
6907 index = package->extensions[i].ComponentIndex;
6908 f_index = package->extensions[i].FeatureIndex;
6910 if (index < 0)
6911 continue;
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));
6926 continue;
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
6935 * according to MSDN
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);
6944 extension[0] = '.';
6945 extension[1] = 0;
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};
6964 HKEY hkey2;
6965 LPWSTR newkey;
6966 LPCWSTR progid;
6967 INT v;
6968 INT Sequence = MSI_NULL_INTEGER;
6970 if (package->extensions[i].ProgIDIndex >= 0)
6971 progid = package->progids[package->extensions[i].
6972 ProgIDIndex].ProgID;
6973 else
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);
6985 RegCloseKey(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]],
6995 &Sequence);
6998 RegCloseKey(hkey);
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 };
7013 HKEY hkey;
7014 INT i;
7015 MSIRECORD *uirow;
7017 if (!package)
7018 return ERROR_INVALID_HANDLE;
7020 load_classes_and_such(package);
7022 for (i = 0; i < package->loaded_mimes; i++)
7024 WCHAR extension[257];
7025 LPCWSTR exten;
7026 LPCWSTR mime;
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};
7030 LPWSTR key;
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));
7046 continue;
7049 mime = package->mimes[i].ContentType;
7050 exten = package->extensions[package->mimes[i].ExtensionIndex].Extension;
7051 extension[0] = '.';
7052 extension[1] = 0;
7053 strcatW(extension,exten);
7055 key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) *
7056 sizeof(WCHAR));
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");
7069 RegCloseKey(hkey);
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};
7085 HKEY hkey=0;
7086 LPWSTR buffer;
7087 LPWSTR productcode;
7088 LPWSTR productid;
7089 UINT rc,i;
7090 DWORD size;
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},
7097 {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},
7105 {0},
7108 if (!package)
7109 return ERROR_INVALID_HANDLE;
7111 productid = load_dynamic_property(package,szProductID,&rc);
7112 if (!productid)
7113 return ERROR_SUCCESS;
7115 productcode = load_dynamic_property(package,szProductCode,&rc);
7116 if (!productcode)
7117 return rc;
7119 rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
7120 if (rc != ERROR_SUCCESS)
7121 goto end;
7123 i = 0;
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);
7132 else
7133 RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,NULL,0);
7134 i++;
7137 end:
7138 HeapFree(GetProcessHeap(),0,productcode);
7139 HeapFree(GetProcessHeap(),0,productid);
7140 RegCloseKey(hkey);
7142 return ERROR_SUCCESS;
7146 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
7148 UINT rc;
7149 rc = ACTION_ProcessExecSequence(package,FALSE);
7150 return rc;
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)
7162 HANDLE handle;
7163 LPWSTR ret = NULL;
7164 int i;
7166 typedef struct _tagTT_OFFSET_TABLE{
7167 USHORT uMajorVersion;
7168 USHORT uMinorVersion;
7169 USHORT uNumOfTables;
7170 USHORT uSearchRange;
7171 USHORT uEntrySelector;
7172 USHORT uRangeShift;
7173 }TT_OFFSET_TABLE;
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{
7190 USHORT uPlatformID;
7191 USHORT uEncodingID;
7192 USHORT uLanguageID;
7193 USHORT uNameID;
7194 USHORT uStringLength;
7195 USHORT uStringOffset; /* from start of storage area */
7196 }TT_NAME_RECORD;
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)
7216 return NULL;
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)
7223 bFound = TRUE;
7224 tblDir.uLength = SWAPLONG(tblDir.uLength);
7225 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
7226 break;
7230 if (bFound)
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),
7237 NULL,NULL);
7239 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
7240 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
7241 bFound = FALSE;
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)
7249 int nPos;
7250 LPSTR buf;
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,
7259 NULL, FILE_BEGIN);
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)
7266 strcat(buf,tt);
7267 ret = strdupAtoW(buf);
7268 HeapFree(GetProcessHeap(),0,buf);
7269 break;
7272 HeapFree(GetProcessHeap(),0,buf);
7273 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
7277 CloseHandle(handle);
7279 else
7280 ERR("Unable to open font file %s\n", debugstr_w(filename));
7282 TRACE("Returning fontname %s\n",debugstr_w(ret));
7283 return ret;
7286 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
7288 UINT rc;
7289 MSIQUERY * view;
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};
7306 HKEY hkey1;
7307 HKEY hkey2;
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);
7330 while (1)
7332 LPWSTR name;
7333 LPWSTR file;
7334 UINT index;
7335 DWORD size;
7337 rc = MSI_ViewFetch(view,&row);
7338 if (rc != ERROR_SUCCESS)
7340 rc = ERROR_SUCCESS;
7341 break;
7344 file = load_dynamic_stringW(row,1);
7345 index = get_loaded_file(package,file);
7346 if (index < 0)
7348 ERR("Unable to load file\n");
7349 HeapFree(GetProcessHeap(),0,file);
7350 continue;
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);
7362 continue;
7365 if (MSI_RecordIsNull(row,2))
7366 name = load_ttfname_from(package->files[index].TargetPath);
7367 else
7368 name = load_dynamic_stringW(row,2);
7370 if (name)
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);
7386 RegCloseKey(hkey1);
7387 RegCloseKey(hkey2);
7389 TRACE("returning %d\n", rc);
7390 return rc;
7393 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
7395 MSIPACKAGE *package = (MSIPACKAGE*)param;
7396 LPWSTR compgroupid=NULL;
7397 LPWSTR feature=NULL;
7398 LPWSTR text = NULL;
7399 LPWSTR qualifier = NULL;
7400 LPWSTR component = NULL;
7401 LPWSTR advertise = NULL;
7402 LPWSTR output = NULL;
7403 HKEY hkey;
7404 UINT rc = ERROR_SUCCESS;
7405 UINT index;
7406 DWORD sz = 0;
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)
7429 goto end;
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);
7440 if (text)
7441 sz += lstrlenW(text);
7443 sz+=3;
7444 sz *= sizeof(WCHAR);
7446 output = HeapAlloc(GetProcessHeap(),0,sz);
7447 memset(output,0,sz);
7448 strcpyW(output,advertise);
7450 if (text)
7451 strcatW(output,text);
7453 sz = (lstrlenW(output)+2) * sizeof(WCHAR);
7454 RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz);
7456 end:
7457 RegCloseKey(hkey);
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);
7465 return rc;
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)
7474 UINT rc;
7475 MSIQUERY * view;
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);
7488 return rc;
7491 /* Msi functions that seem appropriate here */
7493 /***********************************************************************
7494 * MsiDoActionA (MSI.@)
7496 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
7498 LPWSTR szwAction;
7499 UINT rc;
7501 TRACE(" exteral attempt at action %s\n",szAction);
7503 if (!szAction)
7504 return ERROR_FUNCTION_FAILED;
7505 if (hInstall == 0)
7506 return ERROR_FUNCTION_FAILED;
7508 szwAction = strdupAtoW(szAction);
7510 if (!szwAction)
7511 return ERROR_FUNCTION_FAILED;
7514 rc = MsiDoActionW(hInstall, szwAction);
7515 HeapFree(GetProcessHeap(),0,szwAction);
7516 return rc;
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);
7530 if( package )
7532 ret = ACTION_PerformUIAction(package,szAction);
7533 msiobj_release( &package->hdr );
7535 return ret;
7538 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
7539 LPSTR szPathBuf, DWORD* pcchPathBuf)
7541 LPWSTR szwFolder;
7542 LPWSTR szwPathBuf;
7543 UINT rc;
7545 TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
7547 if (!szFolder)
7548 return ERROR_FUNCTION_FAILED;
7549 if (hInstall == 0)
7550 return ERROR_FUNCTION_FAILED;
7552 szwFolder = strdupAtoW(szFolder);
7554 if (!szwFolder)
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);
7567 return rc;
7570 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
7571 szPathBuf, DWORD* pcchPathBuf)
7573 LPWSTR path;
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);
7580 if (!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;
7590 else if (path)
7592 *pcchPathBuf = strlenW(path)+1;
7593 strcpyW(szPathBuf,path);
7594 TRACE("Returning Path %s\n",debugstr_w(path));
7595 rc = ERROR_SUCCESS;
7597 HeapFree(GetProcessHeap(),0,path);
7599 return rc;
7603 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder,
7604 LPSTR szPathBuf, DWORD* pcchPathBuf)
7606 LPWSTR szwFolder;
7607 LPWSTR szwPathBuf;
7608 UINT rc;
7610 TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
7612 if (!szFolder)
7613 return ERROR_FUNCTION_FAILED;
7614 if (hInstall == 0)
7615 return ERROR_FUNCTION_FAILED;
7617 szwFolder = strdupAtoW(szFolder);
7618 if (!szwFolder)
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);
7631 return rc;
7634 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
7635 szPathBuf, DWORD* pcchPathBuf)
7637 LPWSTR path;
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);
7644 if( !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;
7654 else if (path)
7656 *pcchPathBuf = strlenW(path)+1;
7657 strcpyW(szPathBuf,path);
7658 TRACE("Returning Path %s\n",debugstr_w(path));
7659 rc = ERROR_SUCCESS;
7661 HeapFree(GetProcessHeap(),0,path);
7663 return rc;
7667 /***********************************************************************
7668 * MsiSetTargetPathA (MSI.@)
7670 UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder,
7671 LPCSTR szFolderPath)
7673 LPWSTR szwFolder;
7674 LPWSTR szwFolderPath;
7675 UINT rc;
7677 if (!szFolder)
7678 return ERROR_FUNCTION_FAILED;
7679 if (hInstall == 0)
7680 return ERROR_FUNCTION_FAILED;
7682 szwFolder = strdupAtoW(szFolder);
7683 if (!szwFolder)
7684 return ERROR_FUNCTION_FAILED;
7686 szwFolderPath = strdupAtoW(szFolderPath);
7687 if (!szwFolderPath)
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);
7698 return rc;
7701 UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
7702 LPCWSTR szFolderPath)
7704 DWORD i;
7705 LPWSTR path = NULL;
7706 LPWSTR path2 = NULL;
7707 MSIFOLDER *folder;
7709 TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
7711 if (package==NULL)
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);
7722 if (!path)
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);
7739 else
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,
7750 TRUE, NULL);
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;
7766 UINT ret;
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 );
7773 return ret;
7776 /***********************************************************************
7777 * MsiGetMode (MSI.@)
7779 * Returns an internal installer state (if it is running in a mode iRunMode)
7781 * PARAMS
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
7804 * RETURNS
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);
7813 return TRUE;
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;
7826 UINT rc;
7828 szwFeature = strdupAtoW(szFeature);
7830 if (!szwFeature)
7831 return ERROR_FUNCTION_FAILED;
7833 rc = MsiSetFeatureStateW(hInstall,szwFeature, iState);
7835 HeapFree(GetProcessHeap(),0,szwFeature);
7837 return rc;
7842 UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
7843 INSTALLSTATE iState)
7845 INT index, i;
7846 UINT rc = ERROR_SUCCESS;
7848 TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
7850 index = get_loaded_feature(package,szFeature);
7851 if (index < 0)
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);
7871 return rc;
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);
7886 if (!package)
7887 return ERROR_INVALID_HANDLE;
7889 rc = MSI_SetFeatureStateW(package,szFeature,iState);
7891 msiobj_release( &package->hdr );
7892 return rc;
7895 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
7896 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7898 LPWSTR szwFeature = NULL;
7899 UINT rc;
7901 szwFeature = strdupAtoW(szFeature);
7903 rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
7905 HeapFree( GetProcessHeap(), 0 , szwFeature);
7907 return rc;
7910 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
7911 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7913 INT index;
7915 index = get_loaded_feature(package,szFeature);
7916 if (index < 0)
7917 return ERROR_UNKNOWN_FEATURE;
7919 if (piInstalled)
7920 *piInstalled = package->features[index].Installed;
7922 if (piAction)
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;
7934 UINT ret;
7936 TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
7937 piAction);
7939 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7940 if (!package)
7941 return ERROR_INVALID_HANDLE;
7942 ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
7943 msiobj_release( &package->hdr );
7944 return ret;
7947 /***********************************************************************
7948 * MsiGetComponentStateA (MSI.@)
7950 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
7951 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7953 LPWSTR szwComponent= NULL;
7954 UINT rc;
7956 szwComponent= strdupAtoW(szComponent);
7958 rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
7960 HeapFree( GetProcessHeap(), 0 , szwComponent);
7962 return rc;
7965 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
7966 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7968 INT index;
7970 TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
7971 piAction);
7973 index = get_loaded_component(package,szComponent);
7974 if (index < 0)
7975 return ERROR_UNKNOWN_COMPONENT;
7977 if (piInstalled)
7978 *piInstalled = package->components[index].Installed;
7980 if (piAction)
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;
7996 UINT ret;
7998 TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
7999 piInstalled, piAction);
8001 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
8002 if (!package)
8003 return ERROR_INVALID_HANDLE;
8004 ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
8005 msiobj_release( &package->hdr );
8006 return ret;