2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
38 #include "wine/debug.h"
43 #include "msvcrt/fcntl.h"
50 #include "wine/unicode.h"
54 #define REG_PROGRESS_VALUE 13200
55 #define COMPONENT_PROGRESS_VALUE 24000
57 WINE_DEFAULT_DEBUG_CHANNEL(msi);
62 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
63 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
64 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
65 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name,
71 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
73 static UINT ACTION_LaunchConditions(MSIPACKAGE *package);
74 static UINT ACTION_CostInitialize(MSIPACKAGE *package);
75 static UINT ACTION_CreateFolders(MSIPACKAGE *package);
76 static UINT ACTION_CostFinalize(MSIPACKAGE *package);
77 static UINT ACTION_FileCost(MSIPACKAGE *package);
78 static UINT ACTION_InstallFiles(MSIPACKAGE *package);
79 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
80 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package);
81 static UINT ACTION_InstallInitialize(MSIPACKAGE *package);
82 static UINT ACTION_InstallValidate(MSIPACKAGE *package);
83 static UINT ACTION_ProcessComponents(MSIPACKAGE *package);
84 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package);
85 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
86 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
87 static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package);
88 static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package);
89 static UINT ACTION_RegisterUser(MSIPACKAGE *package);
90 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package);
91 static UINT ACTION_PublishProduct(MSIPACKAGE *package);
92 static UINT ACTION_WriteIniValues(MSIPACKAGE *package);
93 static UINT ACTION_SelfRegModules(MSIPACKAGE *package);
94 static UINT ACTION_PublishFeatures(MSIPACKAGE *package);
95 static UINT ACTION_RegisterProduct(MSIPACKAGE *package);
96 static UINT ACTION_InstallExecute(MSIPACKAGE *package);
97 static UINT ACTION_InstallFinalize(MSIPACKAGE *package);
98 static UINT ACTION_ForceReboot(MSIPACKAGE *package);
99 static UINT ACTION_ResolveSource(MSIPACKAGE *package);
100 static UINT ACTION_ExecuteAction(MSIPACKAGE *package);
101 static UINT ACTION_RegisterFonts(MSIPACKAGE *package);
102 static UINT ACTION_PublishComponents(MSIPACKAGE *package);
106 * consts and values used
108 static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
109 static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
110 static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
111 static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
112 static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
113 static const WCHAR c_colon[] = {'C',':','\\',0};
114 static const WCHAR szProductCode[]=
115 {'P','r','o','d','u','c','t','C','o','d','e',0};
116 static const WCHAR cszbs[]={'\\',0};
117 const static WCHAR szCreateFolders[] =
118 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
119 const static WCHAR szCostFinalize[] =
120 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
121 const static WCHAR szInstallFiles[] =
122 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
123 const static WCHAR szDuplicateFiles[] =
124 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
125 const static WCHAR szWriteRegistryValues[] =
126 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
127 'V','a','l','u','e','s',0};
128 const static WCHAR szCostInitialize[] =
129 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
130 const static WCHAR szFileCost[] =
131 {'F','i','l','e','C','o','s','t',0};
132 const static WCHAR szInstallInitialize[] =
133 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
134 const static WCHAR szInstallValidate[] =
135 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
136 const static WCHAR szLaunchConditions[] =
137 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
138 const static WCHAR szProcessComponents[] =
139 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
140 const static WCHAR szRegisterTypeLibraries[] =
141 {'R','e','g','i','s','t','e','r','T','y','p','e',
142 'L','i','b','r','a','r','i','e','s',0};
143 const static WCHAR szRegisterClassInfo[] =
144 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
145 const static WCHAR szRegisterProgIdInfo[] =
146 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
147 const static WCHAR szCreateShortcuts[] =
148 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
149 const static WCHAR szPublishProduct[] =
150 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
151 const static WCHAR szWriteIniValues[] =
152 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
153 const static WCHAR szSelfRegModules[] =
154 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
155 const static WCHAR szPublishFeatures[] =
156 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
157 const static WCHAR szRegisterProduct[] =
158 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
159 const static WCHAR szInstallExecute[] =
160 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
161 const static WCHAR szInstallExecuteAgain[] =
162 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
163 'A','g','a','i','n',0};
164 const static WCHAR szInstallFinalize[] =
165 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
166 const static WCHAR szForceReboot[] =
167 {'F','o','r','c','e','R','e','b','o','o','t',0};
168 const static WCHAR szResolveSource[] =
169 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
170 const static WCHAR szAppSearch[] =
171 {'A','p','p','S','e','a','r','c','h',0};
172 const static WCHAR szAllocateRegistrySpace[] =
173 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
174 'S','p','a','c','e',0};
175 const static WCHAR szBindImage[] =
176 {'B','i','n','d','I','m','a','g','e',0};
177 const static WCHAR szCCPSearch[] =
178 {'C','C','P','S','e','a','r','c','h',0};
179 const static WCHAR szDeleteServices[] =
180 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
181 const static WCHAR szDisableRollback[] =
182 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
183 const static WCHAR szExecuteAction[] =
184 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
185 const static WCHAR szFindRelatedProducts[] =
186 {'F','i','n','d','R','e','l','a','t','e','d',
187 'P','r','o','d','u','c','t','s',0};
188 const static WCHAR szInstallAdminPackage[] =
189 {'I','n','s','t','a','l','l','A','d','m','i','n',
190 'P','a','c','k','a','g','e',0};
191 const static WCHAR szInstallSFPCatalogFile[] =
192 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
194 const static WCHAR szIsolateComponents[] =
195 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
196 const static WCHAR szMigrateFeatureStates[] =
197 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
198 'S','t','a','t','e','s',0};
199 const static WCHAR szMoveFiles[] =
200 {'M','o','v','e','F','i','l','e','s',0};
201 const static WCHAR szMsiPublishAssemblies[] =
202 {'M','s','i','P','u','b','l','i','s','h',
203 'A','s','s','e','m','b','l','i','e','s',0};
204 const static WCHAR szMsiUnpublishAssemblies[] =
205 {'M','s','i','U','n','p','u','b','l','i','s','h',
206 'A','s','s','e','m','b','l','i','e','s',0};
207 const static WCHAR szInstallODBC[] =
208 {'I','n','s','t','a','l','l','O','D','B','C',0};
209 const static WCHAR szInstallServices[] =
210 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
211 const static WCHAR szPatchFiles[] =
212 {'P','a','t','c','h','F','i','l','e','s',0};
213 const static WCHAR szPublishComponents[] =
214 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
215 const static WCHAR szRegisterComPlus[] =
216 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
217 const static WCHAR szRegisterExtensionInfo[] =
218 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
220 const static WCHAR szRegisterFonts[] =
221 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
222 const static WCHAR szRegisterMIMEInfo[] =
223 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
224 const static WCHAR szRegisterUser[] =
225 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
226 const static WCHAR szRemoveDuplicateFiles[] =
227 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
228 'F','i','l','e','s',0};
229 const static WCHAR szRemoveEnvironmentStrings[] =
230 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
231 'S','t','r','i','n','g','s',0};
232 const static WCHAR szRemoveExistingProducts[] =
233 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
234 'P','r','o','d','u','c','t','s',0};
235 const static WCHAR szRemoveFiles[] =
236 {'R','e','m','o','v','e','F','i','l','e','s',0};
237 const static WCHAR szRemoveFolders[] =
238 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
239 const static WCHAR szRemoveIniValues[] =
240 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
241 const static WCHAR szRemoveODBC[] =
242 {'R','e','m','o','v','e','O','D','B','C',0};
243 const static WCHAR szRemoveRegistryValues[] =
244 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
245 'V','a','l','u','e','s',0};
246 const static WCHAR szRemoveShortcuts[] =
247 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
248 const static WCHAR szRMCCPSearch[] =
249 {'R','M','C','C','P','S','e','a','r','c','h',0};
250 const static WCHAR szScheduleReboot[] =
251 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
252 const static WCHAR szSelfUnregModules[] =
253 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
254 const static WCHAR szSetODBCFolders[] =
255 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
256 const static WCHAR szStartServices[] =
257 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
258 const static WCHAR szStopServices[] =
259 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
260 const static WCHAR szUnpublishComponents[] =
261 {'U','n','p','u','b','l','i','s','h',
262 'C','o','m','p','o','n','e','n','t','s',0};
263 const static WCHAR szUnpublishFeatures[] =
264 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
265 const static WCHAR szUnregisterClassInfo[] =
266 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
268 const static WCHAR szUnregisterComPlus[] =
269 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
270 const static WCHAR szUnregisterExtensionInfo[] =
271 {'U','n','r','e','g','i','s','t','e','r',
272 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
273 const static WCHAR szUnregisterFonts[] =
274 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
275 const static WCHAR szUnregisterMIMEInfo[] =
276 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
277 const static WCHAR szUnregisterProgIdInfo[] =
278 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
280 const static WCHAR szUnregisterTypeLibraries[] =
281 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
282 'L','i','b','r','a','r','i','e','s',0};
283 const static WCHAR szValidateProductID[] =
284 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
285 const static WCHAR szWriteEnvironmentStrings[] =
286 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
287 'S','t','r','i','n','g','s',0};
291 STANDARDACTIONHANDLER handler;
294 static struct _actions StandardActions[] = {
295 { szAllocateRegistrySpace, NULL},
296 { szAppSearch, ACTION_AppSearch },
297 { szBindImage, NULL},
298 { szCCPSearch, NULL},
299 { szCostFinalize, ACTION_CostFinalize },
300 { szCostInitialize, ACTION_CostInitialize },
301 { szCreateFolders, ACTION_CreateFolders },
302 { szCreateShortcuts, ACTION_CreateShortcuts },
303 { szDeleteServices, NULL},
304 { szDisableRollback, NULL},
305 { szDuplicateFiles, ACTION_DuplicateFiles },
306 { szExecuteAction, ACTION_ExecuteAction },
307 { szFileCost, ACTION_FileCost },
308 { szFindRelatedProducts, NULL},
309 { szForceReboot, ACTION_ForceReboot },
310 { szInstallAdminPackage, NULL},
311 { szInstallExecute, ACTION_InstallExecute },
312 { szInstallExecuteAgain, ACTION_InstallExecute },
313 { szInstallFiles, ACTION_InstallFiles},
314 { szInstallFinalize, ACTION_InstallFinalize },
315 { szInstallInitialize, ACTION_InstallInitialize },
316 { szInstallSFPCatalogFile, NULL},
317 { szInstallValidate, ACTION_InstallValidate },
318 { szIsolateComponents, NULL},
319 { szLaunchConditions, ACTION_LaunchConditions },
320 { szMigrateFeatureStates, NULL},
321 { szMoveFiles, NULL},
322 { szMsiPublishAssemblies, NULL},
323 { szMsiUnpublishAssemblies, NULL},
324 { szInstallODBC, NULL},
325 { szInstallServices, NULL},
326 { szPatchFiles, NULL},
327 { szProcessComponents, ACTION_ProcessComponents },
328 { szPublishComponents, ACTION_PublishComponents },
329 { szPublishFeatures, ACTION_PublishFeatures },
330 { szPublishProduct, ACTION_PublishProduct },
331 { szRegisterClassInfo, ACTION_RegisterClassInfo },
332 { szRegisterComPlus, NULL},
333 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
334 { szRegisterFonts, ACTION_RegisterFonts },
335 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
336 { szRegisterProduct, ACTION_RegisterProduct },
337 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
338 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
339 { szRegisterUser, ACTION_RegisterUser},
340 { szRemoveDuplicateFiles, NULL},
341 { szRemoveEnvironmentStrings, NULL},
342 { szRemoveExistingProducts, NULL},
343 { szRemoveFiles, NULL},
344 { szRemoveFolders, NULL},
345 { szRemoveIniValues, NULL},
346 { szRemoveODBC, NULL},
347 { szRemoveRegistryValues, NULL},
348 { szRemoveShortcuts, NULL},
349 { szResolveSource, ACTION_ResolveSource},
350 { szRMCCPSearch, NULL},
351 { szScheduleReboot, NULL},
352 { szSelfRegModules, ACTION_SelfRegModules },
353 { szSelfUnregModules, NULL},
354 { szSetODBCFolders, NULL},
355 { szStartServices, NULL},
356 { szStopServices, NULL},
357 { szUnpublishComponents, NULL},
358 { szUnpublishFeatures, NULL},
359 { szUnregisterClassInfo, NULL},
360 { szUnregisterComPlus, NULL},
361 { szUnregisterExtensionInfo, NULL},
362 { szUnregisterFonts, NULL},
363 { szUnregisterMIMEInfo, NULL},
364 { szUnregisterProgIdInfo, NULL},
365 { szUnregisterTypeLibraries, NULL},
366 { szValidateProductID, NULL},
367 { szWriteEnvironmentStrings, NULL},
368 { szWriteIniValues, ACTION_WriteIniValues },
369 { szWriteRegistryValues, ACTION_WriteRegistryValues},
374 /********************************************************
375 * helper functions to get around current HACKS and such
376 ********************************************************/
377 inline static void reduce_to_longfilename(WCHAR* filename)
379 LPWSTR p = strchrW(filename,'|');
381 memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR));
384 inline static void reduce_to_shortfilename(WCHAR* filename)
386 LPWSTR p = strchrW(filename,'|');
391 WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
398 if (MSI_RecordIsNull(row,index))
401 rc = MSI_RecordGetStringW(row,index,NULL,&sz);
403 /* having an empty string is different than NULL */
406 ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR));
412 ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
413 rc = MSI_RecordGetStringW(row,index,ret,&sz);
414 if (rc!=ERROR_SUCCESS)
416 ERR("Unable to load dynamic string\n");
417 HeapFree(GetProcessHeap(), 0, ret);
423 LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc)
429 r = MSI_GetPropertyW(package, prop, NULL, &sz);
430 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
437 str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
438 r = MSI_GetPropertyW(package, prop, str, &sz);
439 if (r != ERROR_SUCCESS)
441 HeapFree(GetProcessHeap(),0,str);
449 int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
454 for (i = 0; i < package->loaded_components; i++)
456 if (strcmpW(Component,package->components[i].Component)==0)
465 int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
470 for (i = 0; i < package->loaded_features; i++)
472 if (strcmpW(Feature,package->features[i].Feature)==0)
481 int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
486 for (i = 0; i < package->loaded_files; i++)
488 if (strcmpW(file,package->files[i].File)==0)
497 int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
505 for (i=0; i < package->loaded_files; i++)
506 if (strcmpW(package->files[i].File,name)==0)
509 index = package->loaded_files;
510 package->loaded_files++;
511 if (package->loaded_files== 1)
512 package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
514 package->files = HeapReAlloc(GetProcessHeap(),0,
515 package->files , package->loaded_files * sizeof(MSIFILE));
517 memset(&package->files[index],0,sizeof(MSIFILE));
519 package->files[index].File = strdupW(name);
520 package->files[index].TargetPath = strdupW(path);
521 package->files[index].Temporary = TRUE;
523 TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));
528 static void remove_tracked_tempfiles(MSIPACKAGE* package)
535 for (i = 0; i < package->loaded_files; i++)
537 if (package->files[i].Temporary)
539 TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));
540 DeleteFileW(package->files[i].TargetPath);
546 /* wrapper to resist a need for a full rewrite right now */
547 DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data )
551 MSIRECORD *rec = MSI_CreateRecord(1);
554 MSI_RecordSetStringW(rec,0,ptr);
555 MSI_FormatRecordW(package,rec,NULL,&size);
559 *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
561 MSI_FormatRecordW(package,rec,*data,&size);
564 msiobj_release( &rec->hdr );
565 return sizeof(WCHAR)*size;
567 msiobj_release( &rec->hdr );
574 /* Called when the package is being closed */
575 void ACTION_free_package_structures( MSIPACKAGE* package)
579 TRACE("Freeing package action data\n");
581 remove_tracked_tempfiles(package);
583 /* No dynamic buffers in features */
584 if (package->features && package->loaded_features > 0)
585 HeapFree(GetProcessHeap(),0,package->features);
587 for (i = 0; i < package->loaded_folders; i++)
589 HeapFree(GetProcessHeap(),0,package->folders[i].Directory);
590 HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault);
591 HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault);
592 HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
593 HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource);
594 HeapFree(GetProcessHeap(),0,package->folders[i].Property);
596 if (package->folders && package->loaded_folders > 0)
597 HeapFree(GetProcessHeap(),0,package->folders);
599 for (i = 0; i < package->loaded_components; i++)
600 HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath);
602 if (package->components && package->loaded_components > 0)
603 HeapFree(GetProcessHeap(),0,package->components);
605 for (i = 0; i < package->loaded_files; i++)
607 HeapFree(GetProcessHeap(),0,package->files[i].File);
608 HeapFree(GetProcessHeap(),0,package->files[i].FileName);
609 HeapFree(GetProcessHeap(),0,package->files[i].ShortName);
610 HeapFree(GetProcessHeap(),0,package->files[i].Version);
611 HeapFree(GetProcessHeap(),0,package->files[i].Language);
612 HeapFree(GetProcessHeap(),0,package->files[i].SourcePath);
613 HeapFree(GetProcessHeap(),0,package->files[i].TargetPath);
616 if (package->files && package->loaded_files > 0)
617 HeapFree(GetProcessHeap(),0,package->files);
619 /* clean up extension, progid, class and verb structures */
620 for (i = 0; i < package->loaded_classes; i++)
622 HeapFree(GetProcessHeap(),0,package->classes[i].Description);
623 HeapFree(GetProcessHeap(),0,package->classes[i].FileTypeMask);
624 HeapFree(GetProcessHeap(),0,package->classes[i].IconPath);
625 HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler);
626 HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler32);
627 HeapFree(GetProcessHeap(),0,package->classes[i].Argument);
628 HeapFree(GetProcessHeap(),0,package->classes[i].ProgIDText);
631 if (package->classes && package->loaded_classes > 0)
632 HeapFree(GetProcessHeap(),0,package->classes);
634 for (i = 0; i < package->loaded_extensions; i++)
636 HeapFree(GetProcessHeap(),0,package->extensions[i].ProgIDText);
639 if (package->extensions && package->loaded_extensions > 0)
640 HeapFree(GetProcessHeap(),0,package->extensions);
642 for (i = 0; i < package->loaded_progids; i++)
644 HeapFree(GetProcessHeap(),0,package->progids[i].ProgID);
645 HeapFree(GetProcessHeap(),0,package->progids[i].Description);
646 HeapFree(GetProcessHeap(),0,package->progids[i].IconPath);
649 if (package->progids && package->loaded_progids > 0)
650 HeapFree(GetProcessHeap(),0,package->progids);
652 for (i = 0; i < package->loaded_verbs; i++)
654 HeapFree(GetProcessHeap(),0,package->verbs[i].Verb);
655 HeapFree(GetProcessHeap(),0,package->verbs[i].Command);
656 HeapFree(GetProcessHeap(),0,package->verbs[i].Argument);
659 if (package->verbs && package->loaded_verbs > 0)
660 HeapFree(GetProcessHeap(),0,package->verbs);
662 for (i = 0; i < package->loaded_mimes; i++)
663 HeapFree(GetProcessHeap(),0,package->mimes[i].ContentType);
665 if (package->mimes && package->loaded_mimes > 0)
666 HeapFree(GetProcessHeap(),0,package->mimes);
668 for (i = 0; i < package->loaded_appids; i++)
670 HeapFree(GetProcessHeap(),0,package->appids[i].RemoteServerName);
671 HeapFree(GetProcessHeap(),0,package->appids[i].LocalServer);
672 HeapFree(GetProcessHeap(),0,package->appids[i].ServiceParameters);
673 HeapFree(GetProcessHeap(),0,package->appids[i].DllSurrogate);
676 if (package->appids && package->loaded_appids > 0)
677 HeapFree(GetProcessHeap(),0,package->appids);
681 for (i = 0; i < TOTAL_SCRIPTS; i++)
684 for (j = 0; j < package->script->ActionCount[i]; j++)
685 HeapFree(GetProcessHeap(),0,package->script->Actions[i][j]);
687 HeapFree(GetProcessHeap(),0,package->script->Actions[i]);
689 HeapFree(GetProcessHeap(),0,package->script);
692 HeapFree(GetProcessHeap(),0,package->PackagePath);
694 /* cleanup control event subscriptions */
695 ControlEvent_CleanupSubscriptions(package);
698 static void ce_actiontext(MSIPACKAGE* package, LPCWSTR action)
700 static const WCHAR szActionText[] =
701 {'A','c','t','i','o','n','T','e','x','t',0};
704 row = MSI_CreateRecord(1);
705 MSI_RecordSetStringW(row,1,action);
706 ControlEvent_FireSubscribedEvent(package,szActionText, row);
707 msiobj_release(&row->hdr);
710 static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )
714 row = MSI_CreateRecord(4);
715 MSI_RecordSetInteger(row,1,a);
716 MSI_RecordSetInteger(row,2,b);
717 MSI_RecordSetInteger(row,3,c);
718 MSI_RecordSetInteger(row,4,d);
719 MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);
720 msiobj_release(&row->hdr);
722 msi_dialog_check_messages(NULL);
725 static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
727 static const WCHAR Query_t[] =
728 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
729 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
730 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',
731 ' ','\'','%','s','\'',0};
737 static const WCHAR szActionData[] =
738 {'A','c','t','i','o','n','D','a','t','a',0};
740 if (!package->LastAction || strcmpW(package->LastAction,action))
742 rc = MSI_OpenQuery(package->db, &view, Query_t, action);
743 if (rc != ERROR_SUCCESS)
746 rc = MSI_ViewExecute(view, 0);
747 if (rc != ERROR_SUCCESS)
750 msiobj_release(&view->hdr);
753 rc = MSI_ViewFetch(view,&row);
754 if (rc != ERROR_SUCCESS)
757 msiobj_release(&view->hdr);
761 if (MSI_RecordIsNull(row,3))
763 msiobj_release(&row->hdr);
765 msiobj_release(&view->hdr);
769 /* update the cached actionformat */
770 HeapFree(GetProcessHeap(),0,package->ActionFormat);
771 package->ActionFormat = load_dynamic_stringW(row,3);
773 HeapFree(GetProcessHeap(),0,package->LastAction);
774 package->LastAction = strdupW(action);
776 msiobj_release(&row->hdr);
778 msiobj_release(&view->hdr);
781 MSI_RecordSetStringW(record,0,package->ActionFormat);
783 MSI_FormatRecordW(package,record,message,&size);
785 row = MSI_CreateRecord(1);
786 MSI_RecordSetStringW(row,1,message);
788 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
790 ControlEvent_FireSubscribedEvent(package,szActionData, row);
792 msiobj_release(&row->hdr);
796 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
798 static const WCHAR template_s[]=
799 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
801 static const WCHAR format[] =
802 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
803 static const WCHAR Query_t[] =
804 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
805 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
806 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
807 ' ','\'','%','s','\'',0};
813 WCHAR *ActionText=NULL;
815 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
817 rc = MSI_OpenQuery(package->db, &view, Query_t, action);
818 if (rc != ERROR_SUCCESS)
820 rc = MSI_ViewExecute(view, 0);
821 if (rc != ERROR_SUCCESS)
824 msiobj_release(&view->hdr);
827 rc = MSI_ViewFetch(view,&row);
828 if (rc != ERROR_SUCCESS)
831 msiobj_release(&view->hdr);
835 ActionText = load_dynamic_stringW(row,2);
836 msiobj_release(&row->hdr);
838 msiobj_release(&view->hdr);
840 sprintfW(message,template_s,timet,action,ActionText);
842 row = MSI_CreateRecord(1);
843 MSI_RecordSetStringW(row,1,message);
845 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
846 msiobj_release(&row->hdr);
847 HeapFree(GetProcessHeap(),0,ActionText);
850 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
854 static const WCHAR template_s[]=
855 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
857 static const WCHAR template_e[]=
858 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
859 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
861 static const WCHAR format[] =
862 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
866 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
868 sprintfW(message,template_s,timet,action);
870 sprintfW(message,template_e,timet,action,rc);
872 row = MSI_CreateRecord(1);
873 MSI_RecordSetStringW(row,1,message);
875 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
876 msiobj_release(&row->hdr);
880 * build_directory_name()
882 * This function is to save messing round with directory names
883 * It handles adding backslashes between path segments,
884 * and can add \ at the end of the directory name if told to.
886 * It takes a variable number of arguments.
887 * It always allocates a new string for the result, so make sure
888 * to free the return value when finished with it.
890 * The first arg is the number of path segments that follow.
891 * The arguments following count are a list of path segments.
892 * A path segment may be NULL.
894 * Path segments will be added with a \ separating them.
895 * A \ will not be added after the last segment, however if the
896 * last segment is NULL, then the last character will be a \
899 static LPWSTR build_directory_name(DWORD count, ...)
906 for(i=0; i<count; i++)
908 LPCWSTR str = va_arg(va,LPCWSTR);
910 sz += strlenW(str) + 1;
914 dir = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
918 for(i=0; i<count; i++)
920 LPCWSTR str = va_arg(va,LPCWSTR);
924 if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\\')
930 static BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, INT index,
933 if (package->components[index].Installed == check)
936 if (package->components[index].ActionRequest == check)
942 static BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE* package, INT index,
945 if (package->features[index].Installed == check)
948 if (package->features[index].ActionRequest == check)
955 /****************************************************
956 * TOP level entry points
957 *****************************************************/
959 UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
960 LPCWSTR szCommandLine)
966 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
967 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
968 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
970 MSI_SetPropertyW(package, szAction, szInstall);
972 package->script = HeapAlloc(GetProcessHeap(),0,sizeof(MSISCRIPT));
973 memset(package->script,0,sizeof(MSISCRIPT));
977 LPWSTR p, check, path;
979 package->PackagePath = strdupW(szPackagePath);
980 path = strdupW(szPackagePath);
981 p = strrchrW(path,'\\');
989 HeapFree(GetProcessHeap(),0,path);
990 path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR));
991 GetCurrentDirectoryW(MAX_PATH,path);
995 check = load_dynamic_property(package, cszSourceDir,NULL);
997 MSI_SetPropertyW(package, cszSourceDir, path);
999 HeapFree(GetProcessHeap(), 0, check);
1001 HeapFree(GetProcessHeap(), 0, path);
1007 ptr = (LPWSTR)szCommandLine;
1014 TRACE("Looking at %s\n",debugstr_w(ptr));
1016 ptr2 = strchrW(ptr,'=');
1022 while (*ptr == ' ') ptr++;
1024 prop = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
1025 memcpy(prop,ptr,len*sizeof(WCHAR));
1031 while (*ptr && (quote || (!quote && *ptr!=' ')))
1044 val = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
1045 memcpy(val,ptr2,len*sizeof(WCHAR));
1048 if (strlenW(prop) > 0)
1050 TRACE("Found commandline property (%s) = (%s)\n",
1051 debugstr_w(prop), debugstr_w(val));
1052 MSI_SetPropertyW(package,prop,val);
1054 HeapFree(GetProcessHeap(),0,val);
1055 HeapFree(GetProcessHeap(),0,prop);
1062 if (MSI_GetPropertyW(package,szUILevel,buffer,&sz) == ERROR_SUCCESS)
1064 if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED)
1066 rc = ACTION_ProcessUISequence(package);
1068 if (rc == ERROR_SUCCESS)
1069 rc = ACTION_ProcessExecSequence(package,TRUE);
1072 rc = ACTION_ProcessExecSequence(package,FALSE);
1075 rc = ACTION_ProcessExecSequence(package,FALSE);
1079 /* install was halted but should be considered a success */
1083 package->script->CurrentlyScripting= FALSE;
1085 /* process the ending type action */
1086 if (rc == ERROR_SUCCESS)
1087 ACTION_PerformActionSequence(package,-1,ui);
1088 else if (rc == ERROR_INSTALL_USEREXIT)
1089 ACTION_PerformActionSequence(package,-2,ui);
1090 else if (rc == ERROR_INSTALL_SUSPEND)
1091 ACTION_PerformActionSequence(package,-4,ui);
1093 ACTION_PerformActionSequence(package,-3,ui);
1095 /* finish up running custom actions */
1096 ACTION_FinishCustomActions(package);
1101 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
1105 WCHAR buffer[0x100];
1107 MSIRECORD * row = 0;
1108 static const WCHAR ExecSeqQuery[] =
1109 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1110 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1111 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1112 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
1114 static const WCHAR UISeqQuery[] =
1115 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1116 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
1117 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
1118 ' ', '=',' ','%','i',0};
1121 rc = MSI_OpenQuery(package->db, &view, UISeqQuery, seq);
1123 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
1125 if (rc == ERROR_SUCCESS)
1127 rc = MSI_ViewExecute(view, 0);
1129 if (rc != ERROR_SUCCESS)
1131 MSI_ViewClose(view);
1132 msiobj_release(&view->hdr);
1136 TRACE("Running the actions\n");
1138 rc = MSI_ViewFetch(view,&row);
1139 if (rc != ERROR_SUCCESS)
1145 /* check conditions */
1146 if (!MSI_RecordIsNull(row,2))
1149 cond = load_dynamic_stringW(row,2);
1153 /* this is a hack to skip errors in the condition code */
1154 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
1156 HeapFree(GetProcessHeap(),0,cond);
1157 msiobj_release(&row->hdr);
1161 HeapFree(GetProcessHeap(),0,cond);
1166 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
1167 if (rc != ERROR_SUCCESS)
1169 ERR("Error is %x\n",rc);
1170 msiobj_release(&row->hdr);
1175 rc = ACTION_PerformUIAction(package,buffer);
1177 rc = ACTION_PerformAction(package,buffer, FALSE);
1178 msiobj_release(&row->hdr);
1180 MSI_ViewClose(view);
1181 msiobj_release(&view->hdr);
1189 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
1193 static const WCHAR ExecSeqQuery[] =
1194 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1195 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1196 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1197 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
1198 'O','R','D','E','R',' ', 'B','Y',' ',
1199 '`','S','e','q','u','e','n','c','e','`',0 };
1200 MSIRECORD * row = 0;
1201 static const WCHAR IVQuery[] =
1202 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
1203 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
1204 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
1205 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
1206 ' ','\'', 'I','n','s','t','a','l','l',
1207 'V','a','l','i','d','a','t','e','\'', 0};
1211 if (package->script->ExecuteSequenceRun)
1213 TRACE("Execute Sequence already Run\n");
1214 return ERROR_SUCCESS;
1217 package->script->ExecuteSequenceRun = TRUE;
1219 /* get the sequence number */
1222 rc = MSI_DatabaseOpenViewW(package->db, IVQuery, &view);
1223 if (rc != ERROR_SUCCESS)
1225 rc = MSI_ViewExecute(view, 0);
1226 if (rc != ERROR_SUCCESS)
1228 MSI_ViewClose(view);
1229 msiobj_release(&view->hdr);
1232 rc = MSI_ViewFetch(view,&row);
1233 if (rc != ERROR_SUCCESS)
1235 MSI_ViewClose(view);
1236 msiobj_release(&view->hdr);
1239 seq = MSI_RecordGetInteger(row,1);
1240 msiobj_release(&row->hdr);
1241 MSI_ViewClose(view);
1242 msiobj_release(&view->hdr);
1245 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
1246 if (rc == ERROR_SUCCESS)
1248 rc = MSI_ViewExecute(view, 0);
1250 if (rc != ERROR_SUCCESS)
1252 MSI_ViewClose(view);
1253 msiobj_release(&view->hdr);
1257 TRACE("Running the actions\n");
1261 WCHAR buffer[0x100];
1264 rc = MSI_ViewFetch(view,&row);
1265 if (rc != ERROR_SUCCESS)
1271 /* check conditions */
1272 if (!MSI_RecordIsNull(row,2))
1275 cond = load_dynamic_stringW(row,2);
1279 /* this is a hack to skip errors in the condition code */
1280 if (MSI_EvaluateConditionW(package, cond) ==
1283 HeapFree(GetProcessHeap(),0,cond);
1284 msiobj_release(&row->hdr);
1288 HeapFree(GetProcessHeap(),0,cond);
1293 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
1294 if (rc != ERROR_SUCCESS)
1296 ERR("Error is %x\n",rc);
1297 msiobj_release(&row->hdr);
1301 rc = ACTION_PerformAction(package,buffer, FALSE);
1303 if (rc == ERROR_FUNCTION_NOT_CALLED)
1306 if (rc != ERROR_SUCCESS)
1308 ERR("Execution halted due to error (%i)\n",rc);
1309 msiobj_release(&row->hdr);
1313 msiobj_release(&row->hdr);
1316 MSI_ViewClose(view);
1317 msiobj_release(&view->hdr);
1325 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1329 static const WCHAR ExecSeqQuery [] =
1330 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1331 '`','I','n','s','t','a','l','l',
1332 'U','I','S','e','q','u','e','n','c','e','`',
1333 ' ','W','H','E','R','E',' ',
1334 '`','S','e','q','u','e','n','c','e','`',' ',
1335 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1336 '`','S','e','q','u','e','n','c','e','`',0};
1338 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1340 if (rc == ERROR_SUCCESS)
1342 rc = MSI_ViewExecute(view, 0);
1344 if (rc != ERROR_SUCCESS)
1346 MSI_ViewClose(view);
1347 msiobj_release(&view->hdr);
1351 TRACE("Running the actions \n");
1355 WCHAR buffer[0x100];
1357 MSIRECORD * row = 0;
1359 rc = MSI_ViewFetch(view,&row);
1360 if (rc != ERROR_SUCCESS)
1367 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
1368 if (rc != ERROR_SUCCESS)
1370 ERR("Error is %x\n",rc);
1371 msiobj_release(&row->hdr);
1376 /* check conditions */
1377 if (!MSI_RecordIsNull(row,2))
1380 cond = load_dynamic_stringW(row,2);
1384 /* this is a hack to skip errors in the condition code */
1385 if (MSI_EvaluateConditionW(package, cond) ==
1388 HeapFree(GetProcessHeap(),0,cond);
1389 msiobj_release(&row->hdr);
1390 TRACE("Skipping action: %s (condition is false)\n",
1391 debugstr_w(buffer));
1395 HeapFree(GetProcessHeap(),0,cond);
1399 rc = ACTION_PerformUIAction(package,buffer);
1401 if (rc == ERROR_FUNCTION_NOT_CALLED)
1404 if (rc != ERROR_SUCCESS)
1406 ERR("Execution halted due to error (%i)\n",rc);
1407 msiobj_release(&row->hdr);
1411 msiobj_release(&row->hdr);
1414 MSI_ViewClose(view);
1415 msiobj_release(&view->hdr);
1422 /********************************************************
1423 * ACTION helper functions and functions that perform the actions
1424 *******************************************************/
1425 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
1426 UINT* rc, BOOL force )
1432 if (!run && !package->script->CurrentlyScripting)
1437 if (strcmpW(action,szInstallFinalize) == 0 ||
1438 strcmpW(action,szInstallExecute) == 0 ||
1439 strcmpW(action,szInstallExecuteAgain) == 0)
1444 while (StandardActions[i].action != NULL)
1446 if (strcmpW(StandardActions[i].action, action)==0)
1448 ce_actiontext(package, action);
1451 ui_actioninfo(package, action, TRUE, 0);
1452 *rc = schedule_action(package,INSTALL_SCRIPT,action);
1453 ui_actioninfo(package, action, FALSE, *rc);
1457 ui_actionstart(package, action);
1458 if (StandardActions[i].handler)
1460 *rc = StandardActions[i].handler(package);
1464 FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action));
1465 *rc = ERROR_SUCCESS;
1476 BOOL ACTION_HandleDialogBox(MSIPACKAGE *package, LPCWSTR dialog, UINT* rc)
1480 if (ACTION_DialogBox(package,dialog) == ERROR_SUCCESS)
1482 *rc = package->CurrentInstallState;
1488 BOOL ACTION_HandleCustomAction(MSIPACKAGE* package, LPCWSTR action, UINT* rc,
1494 arc = ACTION_CustomAction(package,action, force);
1496 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1505 * A lot of actions are really important even if they don't do anything
1506 * explicit... Lots of properties are set at the beginning of the installation
1507 * CostFinalize does a bunch of work to translate the directories and such
1509 * But until I get write access to the database that is hard, so I am going to
1510 * hack it to see if I can get something to run.
1512 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
1514 UINT rc = ERROR_SUCCESS;
1517 TRACE("Performing action (%s)\n",debugstr_w(action));
1519 handled = ACTION_HandleStandardAction(package, action, &rc, force);
1522 handled = ACTION_HandleCustomAction(package, action, &rc, force);
1526 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
1527 rc = ERROR_FUNCTION_NOT_CALLED;
1530 package->CurrentInstallState = rc;
1534 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
1536 UINT rc = ERROR_SUCCESS;
1537 BOOL handled = FALSE;
1539 TRACE("Performing action (%s)\n",debugstr_w(action));
1541 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1544 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1547 handled = ACTION_HandleDialogBox(package, action, &rc);
1549 msi_dialog_check_messages( NULL );
1553 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
1554 rc = ERROR_FUNCTION_NOT_CALLED;
1557 package->CurrentInstallState = rc;
1561 /***********************************************************************
1564 * Recursively create all directories in the path.
1566 * shamelessly stolen from setupapi/queue.c
1568 static BOOL create_full_pathW(const WCHAR *path)
1574 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *
1577 strcpyW(new_path, path);
1579 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
1580 new_path[len - 1] = 0;
1582 while(!CreateDirectoryW(new_path, NULL))
1585 DWORD last_error = GetLastError();
1586 if(last_error == ERROR_ALREADY_EXISTS)
1589 if(last_error != ERROR_PATH_NOT_FOUND)
1595 if(!(slash = strrchrW(new_path, '\\')))
1601 len = slash - new_path;
1603 if(!create_full_pathW(new_path))
1608 new_path[len] = '\\';
1611 HeapFree(GetProcessHeap(), 0, new_path);
1616 * Also we cannot enable/disable components either, so for now I am just going
1617 * to do all the directories for all the components.
1619 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1621 static const WCHAR ExecSeqQuery[] =
1622 {'S','E','L','E','C','T',' ',
1623 '`','D','i','r','e','c','t','o','r','y','_','`',
1624 ' ','F','R','O','M',' ',
1625 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1630 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1631 if (rc != ERROR_SUCCESS)
1632 return ERROR_SUCCESS;
1634 rc = MSI_ViewExecute(view, 0);
1635 if (rc != ERROR_SUCCESS)
1637 MSI_ViewClose(view);
1638 msiobj_release(&view->hdr);
1647 MSIRECORD *row = NULL, *uirow;
1649 rc = MSI_ViewFetch(view,&row);
1650 if (rc != ERROR_SUCCESS)
1657 rc = MSI_RecordGetStringW(row,1,dir,&sz);
1659 if (rc!= ERROR_SUCCESS)
1661 ERR("Unable to get folder id \n");
1662 msiobj_release(&row->hdr);
1667 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1670 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1671 msiobj_release(&row->hdr);
1675 TRACE("Folder is %s\n",debugstr_w(full_path));
1678 uirow = MSI_CreateRecord(1);
1679 MSI_RecordSetStringW(uirow,1,full_path);
1680 ui_actiondata(package,szCreateFolders,uirow);
1681 msiobj_release( &uirow->hdr );
1683 if (folder->State == 0)
1684 create_full_pathW(full_path);
1688 msiobj_release(&row->hdr);
1689 HeapFree(GetProcessHeap(),0,full_path);
1691 MSI_ViewClose(view);
1692 msiobj_release(&view->hdr);
1697 static int load_component(MSIPACKAGE* package, MSIRECORD * row)
1699 int index = package->loaded_components;
1702 /* fill in the data */
1704 package->loaded_components++;
1705 if (package->loaded_components == 1)
1706 package->components = HeapAlloc(GetProcessHeap(),0,
1707 sizeof(MSICOMPONENT));
1709 package->components = HeapReAlloc(GetProcessHeap(),0,
1710 package->components, package->loaded_components *
1711 sizeof(MSICOMPONENT));
1713 memset(&package->components[index],0,sizeof(MSICOMPONENT));
1715 sz = IDENTIFIER_SIZE;
1716 MSI_RecordGetStringW(row,1,package->components[index].Component,&sz);
1718 TRACE("Loading Component %s\n",
1719 debugstr_w(package->components[index].Component));
1722 if (!MSI_RecordIsNull(row,2))
1723 MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz);
1725 sz = IDENTIFIER_SIZE;
1726 MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz);
1728 package->components[index].Attributes = MSI_RecordGetInteger(row,4);
1731 MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz);
1733 sz = IDENTIFIER_SIZE;
1734 MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);
1736 package->components[index].Installed = INSTALLSTATE_ABSENT;
1737 package->components[index].Action = INSTALLSTATE_UNKNOWN;
1738 package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN;
1740 package->components[index].Enabled = TRUE;
1745 static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
1747 int index = package->loaded_features;
1749 static const WCHAR Query1[] =
1750 {'S','E','L','E','C','T',' ',
1751 '`','C','o','m','p','o','n','e','n','t','_','`',
1752 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1753 'C','o','m','p','o','n','e','n','t','s','`',' ',
1754 'W','H','E','R','E',' ',
1755 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1756 static const WCHAR Query2[] =
1757 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1758 '`','C','o','m','p','o','n','e','n','t','`',' ',
1759 'W','H','E','R','E',' ',
1760 '`','C','o','m','p','o','n','e','n','t','`',' ',
1761 '=','\'','%','s','\'',0};
1768 /* fill in the data */
1770 package->loaded_features ++;
1771 if (package->loaded_features == 1)
1772 package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE));
1774 package->features = HeapReAlloc(GetProcessHeap(),0,package->features,
1775 package->loaded_features * sizeof(MSIFEATURE));
1777 memset(&package->features[index],0,sizeof(MSIFEATURE));
1779 sz = IDENTIFIER_SIZE;
1780 MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz);
1782 TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature));
1784 sz = IDENTIFIER_SIZE;
1785 if (!MSI_RecordIsNull(row,2))
1786 MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz);
1789 if (!MSI_RecordIsNull(row,3))
1790 MSI_RecordGetStringW(row,3,package->features[index].Title,&sz);
1793 if (!MSI_RecordIsNull(row,4))
1794 MSI_RecordGetStringW(row,4,package->features[index].Description,&sz);
1796 if (!MSI_RecordIsNull(row,5))
1797 package->features[index].Display = MSI_RecordGetInteger(row,5);
1799 package->features[index].Level= MSI_RecordGetInteger(row,6);
1801 sz = IDENTIFIER_SIZE;
1802 if (!MSI_RecordIsNull(row,7))
1803 MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);
1805 package->features[index].Attributes= MSI_RecordGetInteger(row,8);
1807 package->features[index].Installed = INSTALLSTATE_ABSENT;
1808 package->features[index].Action = INSTALLSTATE_UNKNOWN;
1809 package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN;
1811 /* load feature components */
1813 rc = MSI_OpenQuery(package->db, &view, Query1, package->features[index].Feature);
1814 if (rc != ERROR_SUCCESS)
1816 rc = MSI_ViewExecute(view,0);
1817 if (rc != ERROR_SUCCESS)
1819 MSI_ViewClose(view);
1820 msiobj_release(&view->hdr);
1826 WCHAR buffer[0x100];
1829 INT cnt = package->features[index].ComponentCount;
1831 rc = MSI_ViewFetch(view,&row2);
1832 if (rc != ERROR_SUCCESS)
1836 MSI_RecordGetStringW(row2,1,buffer,&sz);
1838 /* check to see if the component is already loaded */
1839 c_indx = get_loaded_component(package,buffer);
1842 TRACE("Component %s already loaded at %i\n", debugstr_w(buffer),
1844 package->features[index].Components[cnt] = c_indx;
1845 package->features[index].ComponentCount ++;
1846 msiobj_release( &row2->hdr );
1850 rc = MSI_OpenQuery(package->db, &view2, Query2, buffer);
1851 if (rc != ERROR_SUCCESS)
1853 msiobj_release( &row2->hdr );
1856 rc = MSI_ViewExecute(view2,0);
1857 if (rc != ERROR_SUCCESS)
1859 msiobj_release( &row2->hdr );
1860 MSI_ViewClose(view2);
1861 msiobj_release( &view2->hdr );
1868 rc = MSI_ViewFetch(view2,&row3);
1869 if (rc != ERROR_SUCCESS)
1871 c_indx = load_component(package,row3);
1872 msiobj_release( &row3->hdr );
1874 package->features[index].Components[cnt] = c_indx;
1875 package->features[index].ComponentCount ++;
1876 TRACE("Loaded new component to index %i\n",c_indx);
1878 MSI_ViewClose(view2);
1879 msiobj_release( &view2->hdr );
1880 msiobj_release( &row2->hdr );
1882 MSI_ViewClose(view);
1883 msiobj_release(&view->hdr);
1886 static UINT load_file(MSIPACKAGE* package, MSIRECORD * row)
1888 DWORD index = package->loaded_files;
1892 /* fill in the data */
1894 package->loaded_files++;
1895 if (package->loaded_files== 1)
1896 package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
1898 package->files = HeapReAlloc(GetProcessHeap(),0,
1899 package->files , package->loaded_files * sizeof(MSIFILE));
1901 memset(&package->files[index],0,sizeof(MSIFILE));
1903 package->files[index].File = load_dynamic_stringW(row, 1);
1904 buffer = load_dynamic_stringW(row, 2);
1906 package->files[index].ComponentIndex = -1;
1907 for (i = 0; i < package->loaded_components; i++)
1908 if (strcmpW(package->components[i].Component,buffer)==0)
1910 package->files[index].ComponentIndex = i;
1913 if (package->files[index].ComponentIndex == -1)
1914 ERR("Unfound Component %s\n",debugstr_w(buffer));
1915 HeapFree(GetProcessHeap(), 0, buffer);
1917 package->files[index].FileName = load_dynamic_stringW(row,3);
1918 reduce_to_longfilename(package->files[index].FileName);
1920 package->files[index].ShortName = load_dynamic_stringW(row,3);
1921 reduce_to_shortfilename(package->files[index].ShortName);
1923 package->files[index].FileSize = MSI_RecordGetInteger(row,4);
1924 package->files[index].Version = load_dynamic_stringW(row, 5);
1925 package->files[index].Language = load_dynamic_stringW(row, 6);
1926 package->files[index].Attributes= MSI_RecordGetInteger(row,7);
1927 package->files[index].Sequence= MSI_RecordGetInteger(row,8);
1929 package->files[index].Temporary = FALSE;
1930 package->files[index].State = 0;
1932 TRACE("File Loaded (%s)\n",debugstr_w(package->files[index].File));
1934 return ERROR_SUCCESS;
1937 static UINT load_all_files(MSIPACKAGE *package)
1942 static const WCHAR Query[] =
1943 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1944 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1945 '`','S','e','q','u','e','n','c','e','`', 0};
1948 return ERROR_INVALID_HANDLE;
1950 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1951 if (rc != ERROR_SUCCESS)
1952 return ERROR_SUCCESS;
1954 rc = MSI_ViewExecute(view, 0);
1955 if (rc != ERROR_SUCCESS)
1957 MSI_ViewClose(view);
1958 msiobj_release(&view->hdr);
1959 return ERROR_SUCCESS;
1964 rc = MSI_ViewFetch(view,&row);
1965 if (rc != ERROR_SUCCESS)
1970 load_file(package,row);
1971 msiobj_release(&row->hdr);
1973 MSI_ViewClose(view);
1974 msiobj_release(&view->hdr);
1976 return ERROR_SUCCESS;
1981 * I am not doing any of the costing functionality yet.
1982 * Mostly looking at doing the Component and Feature loading
1984 * The native MSI does A LOT of modification to tables here. Mostly adding
1985 * a lot of temporary columns to the Feature and Component tables.
1987 * note: Native msi also tracks the short filename. But I am only going to
1988 * track the long ones. Also looking at this directory table
1989 * it appears that the directory table does not get the parents
1990 * resolved base on property only based on their entries in the
1993 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1998 static const WCHAR Query_all[] =
1999 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2000 '`','F','e','a','t','u','r','e','`',0};
2001 static const WCHAR szCosting[] =
2002 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2003 static const WCHAR szZero[] = { '0', 0 };
2007 MSI_GetPropertyW(package, szCosting, buffer, &sz);
2009 return ERROR_SUCCESS;
2011 MSI_SetPropertyW(package, szCosting, szZero);
2012 MSI_SetPropertyW(package, cszRootDrive , c_colon);
2014 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
2015 if (rc != ERROR_SUCCESS)
2017 rc = MSI_ViewExecute(view,0);
2018 if (rc != ERROR_SUCCESS)
2020 MSI_ViewClose(view);
2021 msiobj_release(&view->hdr);
2028 rc = MSI_ViewFetch(view,&row);
2029 if (rc != ERROR_SUCCESS)
2032 load_feature(package,row);
2033 msiobj_release(&row->hdr);
2035 MSI_ViewClose(view);
2036 msiobj_release(&view->hdr);
2038 load_all_files(package);
2040 return ERROR_SUCCESS;
2043 UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action)
2046 LPWSTR *newbuf = NULL;
2047 if (script >= TOTAL_SCRIPTS)
2049 FIXME("Unknown script requested %i\n",script);
2050 return ERROR_FUNCTION_FAILED;
2052 TRACE("Scheduling Action %s in script %i\n",debugstr_w(action), script);
2054 count = package->script->ActionCount[script];
2055 package->script->ActionCount[script]++;
2057 newbuf = HeapReAlloc(GetProcessHeap(),0,
2058 package->script->Actions[script],
2059 package->script->ActionCount[script]* sizeof(LPWSTR));
2061 newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
2063 newbuf[count] = strdupW(action);
2064 package->script->Actions[script] = newbuf;
2066 return ERROR_SUCCESS;
2069 UINT execute_script(MSIPACKAGE *package, UINT script )
2072 UINT rc = ERROR_SUCCESS;
2074 TRACE("Executing Script %i\n",script);
2076 for (i = 0; i < package->script->ActionCount[script]; i++)
2079 action = package->script->Actions[script][i];
2080 ui_actionstart(package, action);
2081 TRACE("Executing Action (%s)\n",debugstr_w(action));
2082 rc = ACTION_PerformAction(package, action, TRUE);
2083 HeapFree(GetProcessHeap(),0,package->script->Actions[script][i]);
2084 if (rc != ERROR_SUCCESS)
2087 HeapFree(GetProcessHeap(),0,package->script->Actions[script]);
2089 package->script->ActionCount[script] = 0;
2090 package->script->Actions[script] = NULL;
2094 static UINT ACTION_FileCost(MSIPACKAGE *package)
2096 return ERROR_SUCCESS;
2100 static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)
2102 static const WCHAR Query[] =
2103 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2104 '`','D','i','r','e','c', 't','o','r','y','`',' ',
2105 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
2106 ' ','=',' ','\'','%','s','\'',
2110 LPWSTR ptargetdir, targetdir, parent, srcdir;
2111 LPWSTR shortname = NULL;
2112 MSIRECORD * row = 0;
2116 TRACE("Looking for dir %s\n",debugstr_w(dir));
2118 for (i = 0; i < package->loaded_folders; i++)
2120 if (strcmpW(package->folders[i].Directory,dir)==0)
2122 TRACE(" %s retuning on index %lu\n",debugstr_w(dir),i);
2127 TRACE("Working to load %s\n",debugstr_w(dir));
2129 index = package->loaded_folders++;
2130 if (package->loaded_folders==1)
2131 package->folders = HeapAlloc(GetProcessHeap(),0,
2134 package->folders= HeapReAlloc(GetProcessHeap(),0,
2135 package->folders, package->loaded_folders*
2138 memset(&package->folders[index],0,sizeof(MSIFOLDER));
2140 package->folders[index].Directory = strdupW(dir);
2142 rc = MSI_OpenQuery(package->db, &view, Query, dir);
2143 if (rc != ERROR_SUCCESS)
2146 rc = MSI_ViewExecute(view, 0);
2147 if (rc != ERROR_SUCCESS)
2149 MSI_ViewClose(view);
2150 msiobj_release(&view->hdr);
2154 rc = MSI_ViewFetch(view,&row);
2155 if (rc != ERROR_SUCCESS)
2157 MSI_ViewClose(view);
2158 msiobj_release(&view->hdr);
2162 ptargetdir = targetdir = load_dynamic_stringW(row,3);
2164 /* split src and target dir */
2165 if (strchrW(targetdir,':'))
2167 srcdir=strchrW(targetdir,':');
2174 /* for now only pick long filename versions */
2175 if (strchrW(targetdir,'|'))
2177 shortname = targetdir;
2178 targetdir = strchrW(targetdir,'|');
2182 /* for the sourcedir pick the short filename */
2183 if (srcdir && strchrW(srcdir,'|'))
2185 LPWSTR p = strchrW(srcdir,'|');
2189 /* now check for root dirs */
2190 if (targetdir[0] == '.' && targetdir[1] == 0)
2193 if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
2198 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
2199 HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault);
2200 package->folders[index].TargetDefault = strdupW(targetdir);
2204 package->folders[index].SourceDefault = strdupW(srcdir);
2206 package->folders[index].SourceDefault = strdupW(shortname);
2208 package->folders[index].SourceDefault = strdupW(targetdir);
2209 HeapFree(GetProcessHeap(), 0, ptargetdir);
2210 TRACE(" SourceDefault = %s\n",debugstr_w(package->folders[index].SourceDefault));
2212 parent = load_dynamic_stringW(row,2);
2215 i = load_folder(package,parent);
2216 package->folders[index].ParentIndex = i;
2217 TRACE("Parent is index %i... %s %s\n",
2218 package->folders[index].ParentIndex,
2219 debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),
2220 debugstr_w(parent));
2223 package->folders[index].ParentIndex = -2;
2224 HeapFree(GetProcessHeap(), 0, parent);
2226 package->folders[index].Property = load_dynamic_property(package, dir,NULL);
2228 msiobj_release(&row->hdr);
2229 MSI_ViewClose(view);
2230 msiobj_release(&view->hdr);
2231 TRACE(" %s retuning on index %i\n",debugstr_w(dir),index);
2236 LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
2237 BOOL set_prop, MSIFOLDER **folder)
2240 LPWSTR p, path = NULL;
2242 TRACE("Working to resolve %s\n",debugstr_w(name));
2244 /* special resolving for Target and Source root dir */
2245 if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
2249 path = load_dynamic_property(package,cszTargetDir,NULL);
2252 path = load_dynamic_property(package,cszRootDrive,NULL);
2254 MSI_SetPropertyW(package,cszTargetDir,path);
2258 for (i = 0; i < package->loaded_folders; i++)
2260 if (strcmpW(package->folders[i].Directory,name)==0)
2263 *folder = &(package->folders[i]);
2269 path = load_dynamic_property(package,cszSourceDir,NULL);
2272 path = load_dynamic_property(package,cszDatabase,NULL);
2275 p = strrchrW(path,'\\');
2282 for (i = 0; i < package->loaded_folders; i++)
2284 if (strcmpW(package->folders[i].Directory,name)==0)
2287 *folder = &(package->folders[i]);
2293 for (i = 0; i < package->loaded_folders; i++)
2295 if (strcmpW(package->folders[i].Directory,name)==0)
2299 if (i >= package->loaded_folders)
2303 *folder = &(package->folders[i]);
2305 if (!source && package->folders[i].ResolvedTarget)
2307 path = strdupW(package->folders[i].ResolvedTarget);
2308 TRACE(" already resolved to %s\n",debugstr_w(path));
2311 else if (source && package->folders[i].ResolvedSource)
2313 path = strdupW(package->folders[i].ResolvedSource);
2314 TRACE(" (source)already resolved to %s\n",debugstr_w(path));
2317 else if (!source && package->folders[i].Property)
2319 path = build_directory_name(2, package->folders[i].Property, NULL);
2321 TRACE(" internally set to %s\n",debugstr_w(path));
2323 MSI_SetPropertyW(package,name,path);
2327 if (package->folders[i].ParentIndex >= 0)
2329 LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;
2331 TRACE(" ! Parent is %s\n", debugstr_w(parent));
2333 p = resolve_folder(package, parent, source, set_prop, NULL);
2336 TRACE(" TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault));
2337 path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL);
2338 package->folders[i].ResolvedTarget = strdupW(path);
2339 TRACE(" resolved into %s\n",debugstr_w(path));
2341 MSI_SetPropertyW(package,name,path);
2345 path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);
2346 TRACE(" (source)resolved into %s\n",debugstr_w(path));
2347 package->folders[i].ResolvedSource = strdupW(path);
2349 HeapFree(GetProcessHeap(),0,p);
2354 /* scan for and update current install states */
2355 void ACTION_UpdateInstallStates(MSIPACKAGE *package)
2360 productcode = load_dynamic_property(package,szProductCode,NULL);
2362 for (i = 0; i < package->loaded_components; i++)
2365 res = MsiGetComponentPathW(productcode,
2366 package->components[i].ComponentId , NULL, NULL);
2368 res = INSTALLSTATE_ABSENT;
2369 package->components[i].Installed = res;
2372 for (i = 0; i < package->loaded_features; i++)
2374 INSTALLSTATE res = -10;
2376 for (j = 0; j < package->features[i].ComponentCount; j++)
2378 MSICOMPONENT* component = &package->components[package->features[i].
2381 res = component->Installed;
2384 if (res == component->Installed)
2387 if (res != component->Installed)
2388 res = INSTALLSTATE_INCOMPLETE;
2394 /* update compoennt state based on a feature change */
2395 void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
2398 INSTALLSTATE newstate;
2399 MSIFEATURE *feature;
2401 i = get_loaded_feature(package,szFeature);
2405 feature = &package->features[i];
2406 newstate = feature->ActionRequest;
2408 for( i = 0; i < feature->ComponentCount; i++)
2410 MSICOMPONENT* component = &package->components[feature->Components[i]];
2412 TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n",
2413 newstate, debugstr_w(component->Component), component->Installed,
2414 component->Action, component->ActionRequest);
2416 if (!component->Enabled)
2420 if (newstate == INSTALLSTATE_LOCAL)
2422 component->ActionRequest = INSTALLSTATE_LOCAL;
2423 component->Action = INSTALLSTATE_LOCAL;
2429 component->ActionRequest = newstate;
2430 component->Action = newstate;
2432 /*if any other feature wants is local we need to set it local*/
2434 j < package->loaded_features &&
2435 component->ActionRequest != INSTALLSTATE_LOCAL;
2438 for (k = 0; k < package->features[j].ComponentCount; k++)
2439 if ( package->features[j].Components[k] ==
2440 feature->Components[i] )
2442 if (package->features[j].ActionRequest ==
2445 TRACE("Saved by %s\n", debugstr_w(package->features[j].Feature));
2446 component->ActionRequest = INSTALLSTATE_LOCAL;
2447 component->Action = INSTALLSTATE_LOCAL;
2454 TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n",
2455 newstate, debugstr_w(component->Component), component->Installed,
2456 component->Action, component->ActionRequest);
2460 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
2463 static const WCHAR all[]={'A','L','L',0};
2464 LPWSTR override = NULL;
2468 override = load_dynamic_property(package, property, NULL);
2472 for(i = 0; i < package->loaded_features; i++)
2474 if (strcmpiW(override,all)==0)
2476 package->features[i].ActionRequest= state;
2477 package->features[i].Action = state;
2481 LPWSTR ptr = override;
2482 LPWSTR ptr2 = strchrW(override,',');
2487 strncmpW(ptr,package->features[i].Feature, ptr2-ptr)==0)
2489 strcmpW(ptr,package->features[i].Feature)==0))
2491 package->features[i].ActionRequest= state;
2492 package->features[i].Action = state;
2498 ptr2 = strchrW(ptr,',');
2505 HeapFree(GetProcessHeap(),0,override);
2511 static UINT SetFeatureStates(MSIPACKAGE *package)
2517 static const WCHAR szlevel[] =
2518 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2519 static const WCHAR szAddLocal[] =
2520 {'A','D','D','L','O','C','A','L',0};
2521 static const WCHAR szRemove[] =
2522 {'R','E','M','O','V','E',0};
2523 BOOL override = FALSE;
2525 /* I do not know if this is where it should happen.. but */
2527 TRACE("Checking Install Level\n");
2529 level = load_dynamic_property(package,szlevel,NULL);
2532 install_level = atoiW(level);
2533 HeapFree(GetProcessHeap(), 0, level);
2538 /* ok hereis the _real_ rub
2539 * all these activation/deactivation things happen in order and things
2540 * later on the list override things earlier on the list.
2541 * 1) INSTALLLEVEL processing
2551 * 11) FILEADDDEFAULT
2552 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
2553 * ignored for all the features. seems strange, especially since it is not
2554 * documented anywhere, but it is how it works.
2556 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
2557 * REMOVE are the big ones, since we don't handle administrative installs
2560 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
2561 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
2565 for(i = 0; i < package->loaded_features; i++)
2567 BOOL feature_state = ((package->features[i].Level > 0) &&
2568 (package->features[i].Level <= install_level));
2570 if ((feature_state) &&
2571 (package->features[i].Action == INSTALLSTATE_UNKNOWN))
2573 if (package->features[i].Attributes &
2574 msidbFeatureAttributesFavorSource)
2576 package->features[i].ActionRequest = INSTALLSTATE_SOURCE;
2577 package->features[i].Action = INSTALLSTATE_SOURCE;
2579 else if (package->features[i].Attributes &
2580 msidbFeatureAttributesFavorAdvertise)
2582 package->features[i].ActionRequest =INSTALLSTATE_ADVERTISED;
2583 package->features[i].Action =INSTALLSTATE_ADVERTISED;
2587 package->features[i].ActionRequest = INSTALLSTATE_LOCAL;
2588 package->features[i].Action = INSTALLSTATE_LOCAL;
2595 * now we want to enable or disable components base on feature
2598 for(i = 0; i < package->loaded_features; i++)
2600 MSIFEATURE* feature = &package->features[i];
2601 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
2602 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2603 feature->ActionRequest);
2605 for( j = 0; j < feature->ComponentCount; j++)
2607 MSICOMPONENT* component = &package->components[
2608 feature->Components[j]];
2610 if (!component->Enabled)
2612 component->Action = INSTALLSTATE_UNKNOWN;
2613 component->ActionRequest = INSTALLSTATE_UNKNOWN;
2617 if (feature->Action == INSTALLSTATE_LOCAL)
2619 component->Action = INSTALLSTATE_LOCAL;
2620 component->ActionRequest = INSTALLSTATE_LOCAL;
2622 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
2624 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
2625 (component->Action == INSTALLSTATE_ABSENT) ||
2626 (component->Action == INSTALLSTATE_ADVERTISED))
2629 component->Action = INSTALLSTATE_SOURCE;
2630 component->ActionRequest = INSTALLSTATE_SOURCE;
2633 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
2635 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
2636 (component->Action == INSTALLSTATE_ABSENT))
2639 component->Action = INSTALLSTATE_ADVERTISED;
2640 component->ActionRequest = INSTALLSTATE_ADVERTISED;
2643 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
2645 if (component->Action == INSTALLSTATE_UNKNOWN)
2647 component->Action = INSTALLSTATE_ABSENT;
2648 component->ActionRequest = INSTALLSTATE_ABSENT;
2655 for(i = 0; i < package->loaded_components; i++)
2657 MSICOMPONENT* component= &package->components[i];
2659 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
2660 debugstr_w(component->Component), component->Installed,
2661 component->Action, component->ActionRequest);
2665 return ERROR_SUCCESS;
2669 * A lot is done in this function aside from just the costing.
2670 * The costing needs to be implemented at some point but for now I am going
2671 * to focus on the directory building
2674 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2676 static const WCHAR ExecSeqQuery[] =
2677 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2678 '`','D','i','r','e','c','t','o','r','y','`',0};
2679 static const WCHAR ConditionQuery[] =
2680 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2681 '`','C','o','n','d','i','t','i','o','n','`',0};
2682 static const WCHAR szCosting[] =
2683 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2684 static const WCHAR szlevel[] =
2685 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2686 static const WCHAR szOne[] = { '1', 0 };
2694 MSI_GetPropertyW(package, szCosting, buffer, &sz);
2696 return ERROR_SUCCESS;
2698 TRACE("Building Directory properties\n");
2700 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2701 if (rc == ERROR_SUCCESS)
2703 rc = MSI_ViewExecute(view, 0);
2704 if (rc != ERROR_SUCCESS)
2706 MSI_ViewClose(view);
2707 msiobj_release(&view->hdr);
2715 MSIRECORD * row = 0;
2718 rc = MSI_ViewFetch(view,&row);
2719 if (rc != ERROR_SUCCESS)
2726 MSI_RecordGetStringW(row,1,name,&sz);
2728 /* This helper function now does ALL the work */
2729 TRACE("Dir %s ...\n",debugstr_w(name));
2730 load_folder(package,name);
2731 path = resolve_folder(package,name,FALSE,TRUE,NULL);
2732 TRACE("resolves to %s\n",debugstr_w(path));
2733 HeapFree( GetProcessHeap(), 0, path);
2735 msiobj_release(&row->hdr);
2737 MSI_ViewClose(view);
2738 msiobj_release(&view->hdr);
2741 TRACE("File calculations %i files\n",package->loaded_files);
2743 for (i = 0; i < package->loaded_files; i++)
2745 MSICOMPONENT* comp = NULL;
2746 MSIFILE* file= NULL;
2748 file = &package->files[i];
2749 if (file->ComponentIndex >= 0)
2750 comp = &package->components[file->ComponentIndex];
2752 if (file->Temporary == TRUE)
2759 /* calculate target */
2760 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
2762 HeapFree(GetProcessHeap(),0,file->TargetPath);
2764 TRACE("file %s is named %s\n",
2765 debugstr_w(file->File),debugstr_w(file->FileName));
2767 file->TargetPath = build_directory_name(2, p, file->FileName);
2769 HeapFree(GetProcessHeap(),0,p);
2771 TRACE("file %s resolves to %s\n",
2772 debugstr_w(file->File),debugstr_w(file->TargetPath));
2774 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2777 comp->Cost += file->FileSize;
2787 static const WCHAR name[] =
2789 static const WCHAR name_fmt[] =
2790 {'%','u','.','%','u','.','%','u','.','%','u',0};
2791 WCHAR filever[0x100];
2792 VS_FIXEDFILEINFO *lpVer;
2794 TRACE("Version comparison.. \n");
2795 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
2796 version = HeapAlloc(GetProcessHeap(),0,versize);
2797 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
2799 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
2801 sprintfW(filever,name_fmt,
2802 HIWORD(lpVer->dwFileVersionMS),
2803 LOWORD(lpVer->dwFileVersionMS),
2804 HIWORD(lpVer->dwFileVersionLS),
2805 LOWORD(lpVer->dwFileVersionLS));
2807 TRACE("new %s old %s\n", debugstr_w(file->Version),
2808 debugstr_w(filever));
2809 if (strcmpiW(filever,file->Version)<0)
2812 FIXME("cost should be diff in size\n");
2813 comp->Cost += file->FileSize;
2817 HeapFree(GetProcessHeap(),0,version);
2825 TRACE("Evaluating Condition Table\n");
2827 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2828 if (rc == ERROR_SUCCESS)
2830 rc = MSI_ViewExecute(view, 0);
2831 if (rc != ERROR_SUCCESS)
2833 MSI_ViewClose(view);
2834 msiobj_release(&view->hdr);
2840 WCHAR Feature[0x100];
2841 MSIRECORD * row = 0;
2845 rc = MSI_ViewFetch(view,&row);
2847 if (rc != ERROR_SUCCESS)
2854 MSI_RecordGetStringW(row,1,Feature,&sz);
2856 feature_index = get_loaded_feature(package,Feature);
2857 if (feature_index < 0)
2858 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));
2862 Condition = load_dynamic_stringW(row,3);
2864 if (MSI_EvaluateConditionW(package,Condition) ==
2867 int level = MSI_RecordGetInteger(row,2);
2868 TRACE("Reseting feature %s to level %i\n",
2869 debugstr_w(Feature), level);
2870 package->features[feature_index].Level = level;
2872 HeapFree(GetProcessHeap(),0,Condition);
2875 msiobj_release(&row->hdr);
2877 MSI_ViewClose(view);
2878 msiobj_release(&view->hdr);
2881 TRACE("Enabling or Disabling Components\n");
2882 for (i = 0; i < package->loaded_components; i++)
2884 if (package->components[i].Condition[0])
2886 if (MSI_EvaluateConditionW(package,
2887 package->components[i].Condition) == MSICONDITION_FALSE)
2889 TRACE("Disabling component %s\n",
2890 debugstr_w(package->components[i].Component));
2891 package->components[i].Enabled = FALSE;
2896 MSI_SetPropertyW(package,szCosting,szOne);
2897 /* set default run level if not set */
2898 level = load_dynamic_property(package,szlevel,NULL);
2900 MSI_SetPropertyW(package,szlevel, szOne);
2902 HeapFree(GetProcessHeap(),0,level);
2904 ACTION_UpdateInstallStates(package);
2906 return SetFeatureStates(package);
2910 * This is a helper function for handling embedded cabinet media
2912 static UINT writeout_cabinet_stream(MSIPACKAGE *package, WCHAR* stream_name,
2920 WCHAR tmp[MAX_PATH];
2922 rc = read_raw_stream_data(package->db,stream_name,&data,&size);
2923 if (rc != ERROR_SUCCESS)
2927 if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
2928 GetTempPathW(MAX_PATH,tmp);
2930 GetTempFileNameW(tmp,stream_name,0,source);
2932 track_tempfile(package,strrchrW(source,'\\'), source);
2933 the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2934 FILE_ATTRIBUTE_NORMAL, NULL);
2936 if (the_file == INVALID_HANDLE_VALUE)
2938 ERR("Unable to create file %s\n",debugstr_w(source));
2939 rc = ERROR_FUNCTION_FAILED;
2943 WriteFile(the_file,data,size,&write,NULL);
2944 CloseHandle(the_file);
2945 TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
2947 HeapFree(GetProcessHeap(),0,data);
2952 /* Support functions for FDI functions */
2955 MSIPACKAGE* package;
2960 static void * cabinet_alloc(ULONG cb)
2962 return HeapAlloc(GetProcessHeap(), 0, cb);
2965 static void cabinet_free(void *pv)
2967 HeapFree(GetProcessHeap(), 0, pv);
2970 static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
2973 DWORD dwShareMode = 0;
2974 DWORD dwCreateDisposition = OPEN_EXISTING;
2975 switch (oflag & _O_ACCMODE)
2978 dwAccess = GENERIC_READ;
2979 dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
2982 dwAccess = GENERIC_WRITE;
2983 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2986 dwAccess = GENERIC_READ | GENERIC_WRITE;
2987 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2990 if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
2991 dwCreateDisposition = CREATE_NEW;
2992 else if (oflag & _O_CREAT)
2993 dwCreateDisposition = CREATE_ALWAYS;
2994 return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
2995 dwCreateDisposition, 0, NULL);
2998 static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
3001 if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
3006 static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
3009 if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
3014 static int cabinet_close(INT_PTR hf)
3016 return CloseHandle((HANDLE)hf) ? 0 : -1;
3019 static long cabinet_seek(INT_PTR hf, long dist, int seektype)
3021 /* flags are compatible and so are passed straight through */
3022 return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
3025 static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
3027 /* FIXME: try to do more processing in this function */
3030 case fdintCOPY_FILE:
3032 CabData *data = (CabData*) pfdin->pv;
3033 ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
3038 LPWSTR tracknametmp;
3039 static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
3041 if (data->file_name && lstrcmpiA(data->file_name,pfdin->psz1))
3044 file = cabinet_alloc((len+1)*sizeof(char));
3045 strcpy(file, data->cab_path);
3046 strcat(file, pfdin->psz1);
3048 TRACE("file: %s\n", debugstr_a(file));
3050 /* track this file so it can be deleted if not installed */
3051 trackpath=strdupAtoW(file);
3052 tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
3053 trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) +
3054 strlenW(tmpprefix)+1) * sizeof(WCHAR));
3056 strcpyW(trackname,tmpprefix);
3057 strcatW(trackname,tracknametmp);
3059 track_tempfile(data->package, trackname, trackpath);
3061 HeapFree(GetProcessHeap(),0,trackpath);
3062 HeapFree(GetProcessHeap(),0,trackname);
3063 HeapFree(GetProcessHeap(),0,tracknametmp);
3065 return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
3067 case fdintCLOSE_FILE_INFO:
3071 if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
3073 if (!LocalFileTimeToFileTime(&ft, &ftLocal))
3075 if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
3078 cabinet_close(pfdin->hf);
3086 /***********************************************************************
3087 * extract_cabinet_file
3089 * Extract files from a cab file.
3091 static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source,
3092 const WCHAR* path, const WCHAR* file)
3102 TRACE("Extracting %s (%s) to %s\n",debugstr_w(source),
3103 debugstr_w(file), debugstr_w(path));
3105 hfdi = FDICreate(cabinet_alloc,
3116 ERR("FDICreate failed\n");
3120 if (!(cabinet = strdupWtoA( source )))
3125 if (!(cab_path = strdupWtoA( path )))
3128 HeapFree(GetProcessHeap(), 0, cabinet);
3132 data.package = package;
3133 data.cab_path = cab_path;
3135 file_name = strdupWtoA(file);
3138 data.file_name = file_name;
3140 ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
3143 ERR("FDICopy failed\n");
3147 HeapFree(GetProcessHeap(), 0, cabinet);
3148 HeapFree(GetProcessHeap(), 0, cab_path);
3149 HeapFree(GetProcessHeap(), 0, file_name);
3154 static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path,
3159 MSIRECORD * row = 0;
3160 static WCHAR source[MAX_PATH];
3161 static const WCHAR ExecSeqQuery[] =
3162 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3163 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3164 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
3165 ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ',
3166 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0};
3171 static UINT last_sequence = 0;
3173 if (file->Attributes & msidbFileAttributesNoncompressed)
3175 TRACE("Uncompressed File, no media to ready.\n");
3176 return ERROR_SUCCESS;
3179 if (file->Sequence <= last_sequence)
3181 TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence);
3182 /*extract_a_cabinet_file(package, source,path,file->File); */
3183 return ERROR_SUCCESS;
3186 sprintfW(Query,ExecSeqQuery,file->Sequence);
3188 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3189 if (rc != ERROR_SUCCESS)
3192 rc = MSI_ViewExecute(view, 0);
3193 if (rc != ERROR_SUCCESS)
3195 MSI_ViewClose(view);
3196 msiobj_release(&view->hdr);
3200 rc = MSI_ViewFetch(view,&row);
3201 if (rc != ERROR_SUCCESS)
3203 MSI_ViewClose(view);
3204 msiobj_release(&view->hdr);
3207 seq = MSI_RecordGetInteger(row,2);
3208 last_sequence = seq;
3210 if (!MSI_RecordIsNull(row,4))
3213 MSI_RecordGetStringW(row,4,cab,&sz);
3214 TRACE("Source is CAB %s\n",debugstr_w(cab));
3215 /* the stream does not contain the # character */
3218 writeout_cabinet_stream(package,&cab[1],source);
3219 strcpyW(path,source);
3220 *(strrchrW(path,'\\')+1)=0;
3225 if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
3227 ERR("No Source dir defined \n");
3228 rc = ERROR_FUNCTION_FAILED;
3232 strcpyW(path,source);
3233 strcatW(source,cab);
3234 /* extract the cab file into a folder in the temp folder */
3236 if (MSI_GetPropertyW(package, cszTempFolder,path, &sz)
3238 GetTempPathW(MAX_PATH,path);
3241 rc = !extract_a_cabinet_file(package, source,path,NULL);
3246 MSI_GetPropertyW(package,cszSourceDir,source,&sz);
3247 strcpyW(path,source);
3249 msiobj_release(&row->hdr);
3250 MSI_ViewClose(view);
3251 msiobj_release(&view->hdr);
3255 inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
3257 UINT rc = ERROR_SUCCESS;
3259 LPWSTR install_path;
3261 install_path = resolve_folder(package, package->components[component].Directory,
3262 FALSE, FALSE, &folder);
3264 return ERROR_FUNCTION_FAILED;
3266 /* create the path */
3267 if (folder->State == 0)
3269 create_full_pathW(install_path);
3272 HeapFree(GetProcessHeap(), 0, install_path);
3277 static UINT ACTION_InstallFiles(MSIPACKAGE *package)
3279 UINT rc = ERROR_SUCCESS;
3282 WCHAR uipath[MAX_PATH];
3285 return ERROR_INVALID_HANDLE;
3287 /* increment progress bar each time action data is sent */
3288 ui_progress(package,1,1,0,0);
3290 for (index = 0; index < package->loaded_files; index++)
3292 WCHAR path_to_source[MAX_PATH];
3295 file = &package->files[index];
3297 if (file->Temporary)
3301 if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex,
3302 INSTALLSTATE_LOCAL))
3304 ui_progress(package,2,file->FileSize,0,0);
3305 TRACE("File %s is not scheduled for install\n",
3306 debugstr_w(file->File));
3311 if ((file->State == 1) || (file->State == 2))
3314 MSICOMPONENT* comp = NULL;
3316 TRACE("Installing %s\n",debugstr_w(file->File));
3317 rc = ready_media_for_file(package, path_to_source, file);
3320 * our file table could change here because a new temp file
3321 * may have been created
3323 file = &package->files[index];
3324 if (rc != ERROR_SUCCESS)
3326 ERR("Unable to ready media\n");
3327 rc = ERROR_FUNCTION_FAILED;
3331 create_component_directory( package, file->ComponentIndex);
3333 /* recalculate file paths because things may have changed */
3335 if (file->ComponentIndex >= 0)
3336 comp = &package->components[file->ComponentIndex];
3338 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
3339 HeapFree(GetProcessHeap(),0,file->TargetPath);
3341 file->TargetPath = build_directory_name(2, p, file->FileName);
3342 HeapFree(GetProcessHeap(),0,p);
3344 if (file->Attributes & msidbFileAttributesNoncompressed)
3346 p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
3347 file->SourcePath = build_directory_name(2, p, file->ShortName);
3348 HeapFree(GetProcessHeap(),0,p);
3351 file->SourcePath = build_directory_name(2, path_to_source,
3355 TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
3356 debugstr_w(file->TargetPath));
3359 uirow=MSI_CreateRecord(9);
3360 MSI_RecordSetStringW(uirow,1,file->File);
3361 strcpyW(uipath,file->TargetPath);
3362 *(strrchrW(uipath,'\\')+1)=0;
3363 MSI_RecordSetStringW(uirow,9,uipath);
3364 MSI_RecordSetInteger(uirow,6,file->FileSize);
3365 ui_actiondata(package,szInstallFiles,uirow);
3366 msiobj_release( &uirow->hdr );
3367 ui_progress(package,2,file->FileSize,0,0);
3370 if (file->Attributes & msidbFileAttributesNoncompressed)
3371 rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
3373 rc = MoveFileW(file->SourcePath, file->TargetPath);
3377 rc = GetLastError();
3378 ERR("Unable to move/copy file (%s -> %s) (error %d)\n",
3379 debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
3381 if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
3383 if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE))
3384 ERR("Unable to copy file (%s -> %s) (error %ld)\n",
3385 debugstr_w(file->SourcePath),
3386 debugstr_w(file->TargetPath), GetLastError());
3387 if (!(file->Attributes & msidbFileAttributesNoncompressed))
3388 DeleteFileW(file->SourcePath);
3391 else if (rc == ERROR_FILE_NOT_FOUND)
3393 ERR("Source File Not Found! Continuing\n");
3396 else if (file->Attributes & msidbFileAttributesVital)
3398 ERR("Ignoring Error and continuing (nonvital file)...\n");
3413 inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
3414 LPWSTR* file_source)
3419 return ERROR_INVALID_HANDLE;
3421 for (index = 0; index < package->loaded_files; index ++)
3423 if (strcmpW(file_key,package->files[index].File)==0)
3425 if (package->files[index].State >= 2)
3427 *file_source = strdupW(package->files[index].TargetPath);
3428 return ERROR_SUCCESS;
3431 return ERROR_FILE_NOT_FOUND;
3435 return ERROR_FUNCTION_FAILED;
3438 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
3442 MSIRECORD * row = 0;
3443 static const WCHAR ExecSeqQuery[] =
3444 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3445 '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0};
3448 return ERROR_INVALID_HANDLE;
3450 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3451 if (rc != ERROR_SUCCESS)
3452 return ERROR_SUCCESS;
3454 rc = MSI_ViewExecute(view, 0);
3455 if (rc != ERROR_SUCCESS)
3457 MSI_ViewClose(view);
3458 msiobj_release(&view->hdr);
3464 WCHAR file_key[0x100];
3465 WCHAR *file_source = NULL;
3466 WCHAR dest_name[0x100];
3467 LPWSTR dest_path, dest;
3468 WCHAR component[0x100];
3469 INT component_index;
3473 rc = MSI_ViewFetch(view,&row);
3474 if (rc != ERROR_SUCCESS)
3481 rc = MSI_RecordGetStringW(row,2,component,&sz);
3482 if (rc != ERROR_SUCCESS)
3484 ERR("Unable to get component\n");
3485 msiobj_release(&row->hdr);
3489 component_index = get_loaded_component(package,component);
3491 if (!ACTION_VerifyComponentForAction(package, component_index,
3492 INSTALLSTATE_LOCAL))
3494 TRACE("Skipping copy due to disabled component\n");
3496 /* the action taken was the same as the current install state */
3497 package->components[component_index].Action =
3498 package->components[component_index].Installed;
3500 msiobj_release(&row->hdr);
3504 package->components[component_index].Action = INSTALLSTATE_LOCAL;
3507 rc = MSI_RecordGetStringW(row,3,file_key,&sz);
3508 if (rc != ERROR_SUCCESS)
3510 ERR("Unable to get file key\n");
3511 msiobj_release(&row->hdr);
3515 rc = get_file_target(package,file_key,&file_source);
3517 if (rc != ERROR_SUCCESS)
3519 ERR("Original file unknown %s\n",debugstr_w(file_key));
3520 msiobj_release(&row->hdr);
3521 HeapFree(GetProcessHeap(),0,file_source);
3525 if (MSI_RecordIsNull(row,4))
3527 strcpyW(dest_name,strrchrW(file_source,'\\')+1);
3532 MSI_RecordGetStringW(row,4,dest_name,&sz);
3533 reduce_to_longfilename(dest_name);
3536 if (MSI_RecordIsNull(row,5))
3539 dest_path = strdupW(file_source);
3540 p = strrchrW(dest_path,'\\');
3546 WCHAR destkey[0x100];
3548 MSI_RecordGetStringW(row,5,destkey,&sz);
3550 dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
3553 ERR("Unable to get destination folder\n");
3554 msiobj_release(&row->hdr);
3555 HeapFree(GetProcessHeap(),0,file_source);
3560 dest = build_directory_name(2, dest_path, dest_name);
3562 TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
3565 if (strcmpW(file_source,dest))
3566 rc = !CopyFileW(file_source,dest,TRUE);
3570 if (rc != ERROR_SUCCESS)
3571 ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError());
3573 FIXME("We should track these duplicate files as well\n");
3575 msiobj_release(&row->hdr);
3576 HeapFree(GetProcessHeap(),0,dest_path);
3577 HeapFree(GetProcessHeap(),0,dest);
3578 HeapFree(GetProcessHeap(),0,file_source);
3580 MSI_ViewClose(view);
3581 msiobj_release(&view->hdr);
3586 /* OK this value is "interpreted" and then formatted based on the
3587 first few characters */
3588 static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type,
3592 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
3598 LPWSTR deformated = NULL;
3601 deformat_string(package, &value[2], &deformated);
3603 /* binary value type */
3607 *size = (strlenW(ptr)/2)+1;
3609 *size = strlenW(ptr)/2;
3611 data = HeapAlloc(GetProcessHeap(),0,*size);
3617 /* if uneven pad with a zero in front */
3623 data[count] = (BYTE)strtol(byte,NULL,0);
3625 TRACE("Uneven byte count\n");
3633 data[count] = (BYTE)strtol(byte,NULL,0);
3636 HeapFree(GetProcessHeap(),0,deformated);
3638 TRACE("Data %li bytes(%i)\n",*size,count);
3645 deformat_string(package, &value[1], &deformated);
3648 *size = sizeof(DWORD);
3649 data = HeapAlloc(GetProcessHeap(),0,*size);
3655 if ( (*p < '0') || (*p > '9') )
3661 if (deformated[0] == '-')
3664 TRACE("DWORD %li\n",*(LPDWORD)data);
3666 HeapFree(GetProcessHeap(),0,deformated);
3671 static const WCHAR szMulti[] = {'[','~',']',0};
3680 *type=REG_EXPAND_SZ;
3688 if (strstrW(value,szMulti))
3689 *type = REG_MULTI_SZ;
3691 *size = deformat_string(package, ptr,(LPWSTR*)&data);
3696 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
3700 MSIRECORD * row = 0;
3701 static const WCHAR ExecSeqQuery[] =
3702 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3703 '`','R','e','g','i','s','t','r','y','`',0 };
3706 return ERROR_INVALID_HANDLE;
3708 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3709 if (rc != ERROR_SUCCESS)
3710 return ERROR_SUCCESS;
3712 rc = MSI_ViewExecute(view, 0);
3713 if (rc != ERROR_SUCCESS)
3715 MSI_ViewClose(view);
3716 msiobj_release(&view->hdr);
3720 /* increment progress bar each time action data is sent */
3721 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
3725 static const WCHAR szHCR[] =
3726 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
3727 'R','O','O','T','\\',0};
3728 static const WCHAR szHCU[] =
3729 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
3730 'U','S','E','R','\\',0};
3731 static const WCHAR szHLM[] =
3732 {'H','K','E','Y','_','L','O','C','A','L','_',
3733 'M','A','C','H','I','N','E','\\',0};
3734 static const WCHAR szHU[] =
3735 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
3737 LPSTR value_data = NULL;
3738 HKEY root_key, hkey;
3740 LPWSTR value, key, name, component, deformated;
3742 INT component_index;
3746 BOOL check_first = FALSE;
3748 rc = MSI_ViewFetch(view,&row);
3749 if (rc != ERROR_SUCCESS)
3754 ui_progress(package,2,0,0,0);
3761 component = load_dynamic_stringW(row, 6);
3762 component_index = get_loaded_component(package,component);
3764 if (!ACTION_VerifyComponentForAction(package, component_index,
3765 INSTALLSTATE_LOCAL))
3767 TRACE("Skipping write due to disabled component\n");
3768 msiobj_release(&row->hdr);
3770 package->components[component_index].Action =
3771 package->components[component_index].Installed;
3776 package->components[component_index].Action = INSTALLSTATE_LOCAL;
3778 name = load_dynamic_stringW(row, 4);
3779 if( MSI_RecordIsNull(row,5) && name )
3781 /* null values can have special meanings */
3782 if (name[0]=='-' && name[1] == 0)
3784 msiobj_release(&row->hdr);
3787 else if ((name[0]=='+' && name[1] == 0) ||
3788 (name[0] == '*' && name[1] == 0))
3790 HeapFree(GetProcessHeap(),0,name);
3796 root = MSI_RecordGetInteger(row,2);
3797 key = load_dynamic_stringW(row, 3);
3800 /* get the root key */
3803 case 0: root_key = HKEY_CLASSES_ROOT;
3806 case 1: root_key = HKEY_CURRENT_USER;
3809 case 2: root_key = HKEY_LOCAL_MACHINE;
3812 case 3: root_key = HKEY_USERS;
3816 ERR("Unknown root %i\n",root);
3823 msiobj_release(&row->hdr);
3827 deformat_string(package, key , &deformated);
3828 size = strlenW(deformated) + strlenW(szRoot) + 1;
3829 uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
3830 strcpyW(uikey,szRoot);
3831 strcatW(uikey,deformated);
3833 if (RegCreateKeyW( root_key, deformated, &hkey))
3835 ERR("Could not create key %s\n",debugstr_w(deformated));
3836 msiobj_release(&row->hdr);
3837 HeapFree(GetProcessHeap(),0,deformated);
3840 HeapFree(GetProcessHeap(),0,deformated);
3842 value = load_dynamic_stringW(row,5);
3844 value_data = parse_value(package, value, &type, &size);
3847 static const WCHAR szEmpty[] = {0};
3848 value_data = (LPSTR)strdupW(szEmpty);
3853 deformat_string(package, name, &deformated);
3855 /* get the double nulls to terminate SZ_MULTI */
3856 if (type == REG_MULTI_SZ)
3857 size +=sizeof(WCHAR);
3861 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
3863 RegSetValueExW(hkey, deformated, 0, type, value_data, size);
3868 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
3869 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
3871 TRACE("value %s of %s checked already exists\n",
3872 debugstr_w(deformated), debugstr_w(uikey));
3876 TRACE("Checked and setting value %s of %s\n",
3877 debugstr_w(deformated), debugstr_w(uikey));
3878 RegSetValueExW(hkey, deformated, 0, type, value_data, size);
3882 uirow = MSI_CreateRecord(3);
3883 MSI_RecordSetStringW(uirow,2,deformated);
3884 MSI_RecordSetStringW(uirow,1,uikey);
3887 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
3889 MSI_RecordSetStringW(uirow,3,value);
3891 ui_actiondata(package,szWriteRegistryValues,uirow);
3892 msiobj_release( &uirow->hdr );
3894 HeapFree(GetProcessHeap(),0,value_data);
3895 HeapFree(GetProcessHeap(),0,value);
3896 HeapFree(GetProcessHeap(),0,deformated);
3898 msiobj_release(&row->hdr);
3901 HeapFree(GetProcessHeap(),0,uikey);
3902 HeapFree(GetProcessHeap(),0,key);
3903 HeapFree(GetProcessHeap(),0,name);
3904 HeapFree(GetProcessHeap(),0,component);
3906 MSI_ViewClose(view);
3907 msiobj_release(&view->hdr);
3911 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3913 package->script->CurrentlyScripting = TRUE;
3915 return ERROR_SUCCESS;
3919 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3923 static const WCHAR q1[]=
3924 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3925 '`','R','e','g','i','s','t','r','y','`',0};
3928 MSIRECORD * row = 0;
3931 TRACE(" InstallValidate \n");
3933 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3934 if (rc != ERROR_SUCCESS)
3935 return ERROR_SUCCESS;
3937 rc = MSI_ViewExecute(view, 0);
3938 if (rc != ERROR_SUCCESS)
3940 MSI_ViewClose(view);
3941 msiobj_release(&view->hdr);
3946 rc = MSI_ViewFetch(view,&row);
3947 if (rc != ERROR_SUCCESS)
3954 msiobj_release(&row->hdr);
3956 MSI_ViewClose(view);
3957 msiobj_release(&view->hdr);
3959 total = total + progress * REG_PROGRESS_VALUE;
3960 total = total + package->loaded_components * COMPONENT_PROGRESS_VALUE;
3961 for (i=0; i < package->loaded_files; i++)
3962 total += package->files[i].FileSize;
3963 ui_progress(package,0,total,0,0);
3965 for(i = 0; i < package->loaded_features; i++)
3967 MSIFEATURE* feature = &package->features[i];
3968 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
3969 debugstr_w(feature->Feature), feature->Installed, feature->Action,
3970 feature->ActionRequest);
3973 return ERROR_SUCCESS;
3976 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3979 MSIQUERY * view = NULL;
3980 MSIRECORD * row = 0;
3981 static const WCHAR ExecSeqQuery[] =
3982 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3983 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3984 static const WCHAR title[]=
3985 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3987 TRACE("Checking launch conditions\n");
3989 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3990 if (rc != ERROR_SUCCESS)
3991 return ERROR_SUCCESS;
3993 rc = MSI_ViewExecute(view, 0);
3994 if (rc != ERROR_SUCCESS)
3996 MSI_ViewClose(view);
3997 msiobj_release(&view->hdr);
4002 while (rc == ERROR_SUCCESS)
4005 LPWSTR message = NULL;
4007 rc = MSI_ViewFetch(view,&row);
4008 if (rc != ERROR_SUCCESS)
4014 cond = load_dynamic_stringW(row,1);
4016 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
4019 message = load_dynamic_stringW(row,2);
4020 deformat_string(package,message,&deformated);
4021 MessageBoxW(NULL,deformated,title,MB_OK);
4022 HeapFree(GetProcessHeap(),0,message);
4023 HeapFree(GetProcessHeap(),0,deformated);
4024 rc = ERROR_FUNCTION_FAILED;
4026 HeapFree(GetProcessHeap(),0,cond);
4027 msiobj_release(&row->hdr);
4029 MSI_ViewClose(view);
4030 msiobj_release(&view->hdr);
4034 static LPWSTR resolve_keypath( MSIPACKAGE* package, INT
4037 MSICOMPONENT* cmp = &package->components[component_index];
4039 if (cmp->KeyPath[0]==0)
4041 LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
4044 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
4047 MSIRECORD * row = 0;
4049 LPWSTR key,deformated,buffer,name,deformated_name;
4050 static const WCHAR ExecSeqQuery[] =
4051 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4052 '`','R','e','g','i','s','t','r','y','`',' ',
4053 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
4054 ' ','=',' ' ,'\'','%','s','\'',0 };
4055 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
4056 static const WCHAR fmt2[]=
4057 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
4059 rc = MSI_OpenQuery(package->db,&view,ExecSeqQuery,cmp->KeyPath);
4061 if (rc!=ERROR_SUCCESS)
4064 rc = MSI_ViewExecute(view, 0);
4065 if (rc != ERROR_SUCCESS)
4067 MSI_ViewClose(view);
4068 msiobj_release(&view->hdr);
4072 rc = MSI_ViewFetch(view,&row);
4073 if (rc != ERROR_SUCCESS)
4075 MSI_ViewClose(view);
4076 msiobj_release(&view->hdr);
4080 root = MSI_RecordGetInteger(row,2);
4081 key = load_dynamic_stringW(row, 3);
4082 name = load_dynamic_stringW(row, 4);
4083 deformat_string(package, key , &deformated);
4084 deformat_string(package, name, &deformated_name);
4086 len = strlenW(deformated) + 6;
4087 if (deformated_name)
4088 len+=strlenW(deformated_name);
4090 buffer = HeapAlloc(GetProcessHeap(),0, len *sizeof(WCHAR));
4092 if (deformated_name)
4093 sprintfW(buffer,fmt2,root,deformated,deformated_name);
4095 sprintfW(buffer,fmt,root,deformated);
4097 HeapFree(GetProcessHeap(),0,key);
4098 HeapFree(GetProcessHeap(),0,deformated);
4099 HeapFree(GetProcessHeap(),0,name);
4100 HeapFree(GetProcessHeap(),0,deformated_name);
4101 msiobj_release(&row->hdr);
4102 MSI_ViewClose(view);
4103 msiobj_release(&view->hdr);
4107 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
4109 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
4115 j = get_loaded_file(package,cmp->KeyPath);
4119 LPWSTR p = strdupW(package->files[j].TargetPath);
4126 static HKEY openSharedDLLsKey()
4129 static const WCHAR path[] =
4130 {'S','o','f','t','w','a','r','e','\\',
4131 'M','i','c','r','o','s','o','f','t','\\',
4132 'W','i','n','d','o','w','s','\\',
4133 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4134 'S','h','a','r','e','d','D','L','L','s',0};
4136 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
4140 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
4145 DWORD sz = sizeof(count);
4148 hkey = openSharedDLLsKey();
4149 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
4150 if (rc != ERROR_SUCCESS)
4156 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
4160 hkey = openSharedDLLsKey();
4162 RegSetValueExW(hkey,path,0,REG_DWORD,
4163 (LPBYTE)&count,sizeof(count));
4165 RegDeleteValueW(hkey,path);
4171 * Return TRUE if the count should be written out and FALSE if not
4173 static void ACTION_RefCountComponent( MSIPACKAGE* package, UINT index)
4179 /* only refcount DLLs */
4180 if (package->components[index].KeyPath[0]==0 ||
4181 package->components[index].Attributes &
4182 msidbComponentAttributesRegistryKeyPath ||
4183 package->components[index].Attributes &
4184 msidbComponentAttributesODBCDataSource)
4188 count = ACTION_GetSharedDLLsCount(package->components[index].
4190 write = (count > 0);
4192 if (package->components[index].Attributes &
4193 msidbComponentAttributesSharedDllRefCount)
4197 /* increment counts */
4198 for (j = 0; j < package->loaded_features; j++)
4202 if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_LOCAL))
4205 for (i = 0; i < package->features[j].ComponentCount; i++)
4207 if (package->features[j].Components[i] == index)
4211 /* decrement counts */
4212 for (j = 0; j < package->loaded_features; j++)
4215 if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_ABSENT))
4218 for (i = 0; i < package->features[j].ComponentCount; i++)
4220 if (package->features[j].Components[i] == index)
4225 /* ref count all the files in the component */
4227 for (j = 0; j < package->loaded_files; j++)
4229 if (package->files[j].Temporary)
4231 if (package->files[j].ComponentIndex == index)
4232 ACTION_WriteSharedDLLsCount(package->files[j].TargetPath,count);
4235 /* add a count for permenent */
4236 if (package->components[index].Attributes &
4237 msidbComponentAttributesPermanent)
4240 package->components[index].RefCount = count;
4243 ACTION_WriteSharedDLLsCount(package->components[index].FullKeypath,
4244 package->components[index].RefCount);
4248 * Ok further analysis makes me think that this work is
4249 * actually done in the PublishComponents and PublishFeatures
4250 * step, and not here. It appears like the keypath and all that is
4251 * resolved in this step, however actually written in the Publish steps.
4252 * But we will leave it here for now because it is unclear
4254 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
4257 WCHAR squished_pc[GUID_SIZE];
4258 WCHAR squished_cc[GUID_SIZE];
4261 HKEY hkey=0,hkey2=0;
4264 return ERROR_INVALID_HANDLE;
4266 /* writes the Component and Features values to the registry */
4267 productcode = load_dynamic_property(package,szProductCode,&rc);
4271 rc = MSIREG_OpenComponents(&hkey);
4272 if (rc != ERROR_SUCCESS)
4275 squash_guid(productcode,squished_pc);
4276 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
4277 for (i = 0; i < package->loaded_components; i++)
4279 ui_progress(package,2,0,0,0);
4280 if (package->components[i].ComponentId[0]!=0)
4282 WCHAR *keypath = NULL;
4285 squash_guid(package->components[i].ComponentId,squished_cc);
4287 keypath = resolve_keypath(package,i);
4288 package->components[i].FullKeypath = keypath;
4290 /* do the refcounting */
4291 ACTION_RefCountComponent( package, i);
4293 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
4294 debugstr_w(package->components[i].Component),
4295 debugstr_w(squished_cc),
4296 debugstr_w(package->components[i].FullKeypath),
4297 package->components[i].RefCount);
4299 * Write the keypath out if the component is to be registered
4300 * and delete the key if the component is to be deregistered
4302 if (ACTION_VerifyComponentForAction(package, i,
4303 INSTALLSTATE_LOCAL))
4305 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
4306 if (rc != ERROR_SUCCESS)
4311 RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath,
4312 (strlenW(keypath)+1)*sizeof(WCHAR));
4314 if (package->components[i].Attributes &
4315 msidbComponentAttributesPermanent)
4317 static const WCHAR szPermKey[] =
4318 { '0','0','0','0','0','0','0','0','0','0','0','0',
4319 '0','0','0','0','0','0','0', '0','0','0','0','0',
4320 '0','0','0','0','0','0','0','0',0};
4322 RegSetValueExW(hkey2,szPermKey,0,REG_SZ,
4324 (strlenW(keypath)+1)*sizeof(WCHAR));
4330 uirow = MSI_CreateRecord(3);
4331 MSI_RecordSetStringW(uirow,1,productcode);
4332 MSI_RecordSetStringW(uirow,2,package->components[i].
4334 MSI_RecordSetStringW(uirow,3,keypath);
4335 ui_actiondata(package,szProcessComponents,uirow);
4336 msiobj_release( &uirow->hdr );
4339 else if (ACTION_VerifyComponentForAction(package, i,
4340 INSTALLSTATE_ABSENT))
4344 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
4345 if (rc != ERROR_SUCCESS)
4348 RegDeleteValueW(hkey2,squished_pc);
4350 /* if the key is empty delete it */
4351 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
4353 if (res == ERROR_NO_MORE_ITEMS)
4354 RegDeleteKeyW(hkey,squished_cc);
4357 uirow = MSI_CreateRecord(2);
4358 MSI_RecordSetStringW(uirow,1,productcode);
4359 MSI_RecordSetStringW(uirow,2,package->components[i].
4361 ui_actiondata(package,szProcessComponents,uirow);
4362 msiobj_release( &uirow->hdr );
4367 HeapFree(GetProcessHeap(), 0, productcode);
4380 BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
4381 LPWSTR lpszName, LONG_PTR lParam)
4384 typelib_struct *tl_struct = (typelib_struct*) lParam;
4385 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
4389 if (!IS_INTRESOURCE(lpszName))
4391 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
4395 sz = strlenW(tl_struct->source)+4;
4396 sz *= sizeof(WCHAR);
4398 tl_struct->path = HeapAlloc(GetProcessHeap(),0,sz);
4399 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
4401 TRACE("trying %s\n", debugstr_w(tl_struct->path));
4402 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
4403 if (!SUCCEEDED(res))
4405 HeapFree(GetProcessHeap(),0,tl_struct->path);
4406 tl_struct->path = NULL;
4411 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
4412 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
4414 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
4418 HeapFree(GetProcessHeap(),0,tl_struct->path);
4419 tl_struct->path = NULL;
4421 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
4422 ITypeLib_Release(tl_struct->ptLib);
4427 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
4430 * OK this is a bit confusing.. I am given a _Component key and I believe
4431 * that the file that is being registered as a type library is the "key file
4432 * of that component" which I interpret to mean "The file in the KeyPath of
4437 MSIRECORD * row = 0;
4438 static const WCHAR Query[] =
4439 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4440 '`','T','y','p','e','L','i','b','`',0};
4443 return ERROR_INVALID_HANDLE;
4445 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4446 if (rc != ERROR_SUCCESS)
4447 return ERROR_SUCCESS;
4449 rc = MSI_ViewExecute(view, 0);
4450 if (rc != ERROR_SUCCESS)
4452 MSI_ViewClose(view);
4453 msiobj_release(&view->hdr);
4459 WCHAR component[0x100];
4463 typelib_struct tl_struct;
4465 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
4467 rc = MSI_ViewFetch(view,&row);
4468 if (rc != ERROR_SUCCESS)
4475 MSI_RecordGetStringW(row,3,component,&sz);
4477 index = get_loaded_component(package,component);
4480 msiobj_release(&row->hdr);
4484 if (!ACTION_VerifyComponentForAction(package, index,
4485 INSTALLSTATE_LOCAL))
4487 TRACE("Skipping typelib reg due to disabled component\n");
4488 msiobj_release(&row->hdr);
4490 package->components[index].Action =
4491 package->components[index].Installed;
4496 package->components[index].Action = INSTALLSTATE_LOCAL;
4498 index = get_loaded_file(package,package->components[index].KeyPath);
4502 msiobj_release(&row->hdr);
4506 guid = load_dynamic_stringW(row,1);
4507 module = LoadLibraryExW(package->files[index].TargetPath, NULL,
4508 LOAD_LIBRARY_AS_DATAFILE);
4511 CLSIDFromString(guid, &tl_struct.clsid);
4512 tl_struct.source = strdupW(package->files[index].TargetPath);
4513 tl_struct.path = NULL;
4515 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
4516 (LONG_PTR)&tl_struct);
4518 if (tl_struct.path != NULL)
4521 WCHAR helpid[0x100];
4525 MSI_RecordGetStringW(row,6,helpid,&sz);
4527 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
4528 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
4529 HeapFree(GetProcessHeap(),0,help);
4531 if (!SUCCEEDED(res))
4532 ERR("Failed to register type library %s\n",
4533 debugstr_w(tl_struct.path));
4536 ui_actiondata(package,szRegisterTypeLibraries,row);
4538 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
4541 ITypeLib_Release(tl_struct.ptLib);
4542 HeapFree(GetProcessHeap(),0,tl_struct.path);
4545 ERR("Failed to load type library %s\n",
4546 debugstr_w(tl_struct.source));
4548 FreeLibrary(module);
4549 HeapFree(GetProcessHeap(),0,tl_struct.source);
4552 ERR("Could not load file! %s\n",
4553 debugstr_w(package->files[index].TargetPath));
4554 msiobj_release(&row->hdr);
4556 MSI_ViewClose(view);
4557 msiobj_release(&view->hdr);
4561 static INT load_appid(MSIPACKAGE* package, MSIRECORD *row)
4563 DWORD index = package->loaded_appids;
4567 /* fill in the data */
4569 package->loaded_appids++;
4570 if (package->loaded_appids == 1)
4571 package->appids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIAPPID));
4573 package->appids = HeapReAlloc(GetProcessHeap(),0,
4574 package->appids, package->loaded_appids * sizeof(MSIAPPID));
4576 memset(&package->appids[index],0,sizeof(MSIAPPID));
4578 sz = IDENTIFIER_SIZE;
4579 MSI_RecordGetStringW(row, 1, package->appids[index].AppID, &sz);
4580 TRACE("loading appid %s\n",debugstr_w(package->appids[index].AppID));
4582 buffer = load_dynamic_stringW(row,2);
4583 deformat_string(package,buffer,&package->appids[index].RemoteServerName);
4584 HeapFree(GetProcessHeap(),0,buffer);
4586 package->appids[index].LocalServer = load_dynamic_stringW(row,3);
4587 package->appids[index].ServiceParameters = load_dynamic_stringW(row,4);
4588 package->appids[index].DllSurrogate = load_dynamic_stringW(row,5);
4590 package->appids[index].ActivateAtStorage = !MSI_RecordIsNull(row,6);
4591 package->appids[index].RunAsInteractiveUser = !MSI_RecordIsNull(row,7);
4596 static INT load_given_appid(MSIPACKAGE *package, LPCWSTR appid)
4602 static const WCHAR ExecSeqQuery[] =
4603 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4604 '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ',
4605 '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0};
4610 /* check for appids already loaded */
4611 for (i = 0; i < package->loaded_appids; i++)
4612 if (strcmpiW(package->appids[i].AppID,appid)==0)
4614 TRACE("found appid %s at index %i\n",debugstr_w(appid),i);
4618 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, appid);
4619 if (rc != ERROR_SUCCESS)
4622 rc = MSI_ViewExecute(view, 0);
4623 if (rc != ERROR_SUCCESS)
4625 MSI_ViewClose(view);
4626 msiobj_release(&view->hdr);
4630 rc = MSI_ViewFetch(view,&row);
4631 if (rc != ERROR_SUCCESS)
4633 MSI_ViewClose(view);
4634 msiobj_release(&view->hdr);
4638 rc = load_appid(package, row);
4639 msiobj_release(&row->hdr);
4640 MSI_ViewClose(view);
4641 msiobj_release(&view->hdr);
4646 static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid);
4647 static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid);
4649 static INT load_progid(MSIPACKAGE* package, MSIRECORD *row)
4651 DWORD index = package->loaded_progids;
4654 /* fill in the data */
4656 package->loaded_progids++;
4657 if (package->loaded_progids == 1)
4658 package->progids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIPROGID));
4660 package->progids = HeapReAlloc(GetProcessHeap(),0,
4661 package->progids , package->loaded_progids * sizeof(MSIPROGID));
4663 memset(&package->progids[index],0,sizeof(MSIPROGID));
4665 package->progids[index].ProgID = load_dynamic_stringW(row,1);
4666 TRACE("loading progid %s\n",debugstr_w(package->progids[index].ProgID));
4668 buffer = load_dynamic_stringW(row,2);
4669 package->progids[index].ParentIndex = load_given_progid(package,buffer);
4670 if (package->progids[index].ParentIndex < 0 && buffer)
4671 FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer));
4672 HeapFree(GetProcessHeap(),0,buffer);
4674 buffer = load_dynamic_stringW(row,3);
4675 package->progids[index].ClassIndex = load_given_class(package,buffer);
4676 if (package->progids[index].ClassIndex< 0 && buffer)
4677 FIXME("Unknown class %s\n",debugstr_w(buffer));
4678 HeapFree(GetProcessHeap(),0,buffer);
4680 package->progids[index].Description = load_dynamic_stringW(row,4);
4682 if (!MSI_RecordIsNull(row,6))
4684 INT icon_index = MSI_RecordGetInteger(row,6);
4685 LPWSTR FileName = load_dynamic_stringW(row,5);
4687 static const WCHAR fmt[] = {'%','s',',','%','i',0};
4689 build_icon_path(package,FileName,&FilePath);
4691 package->progids[index].IconPath =
4692 HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+10)*
4695 sprintfW(package->progids[index].IconPath,fmt,FilePath,icon_index);
4697 HeapFree(GetProcessHeap(),0,FilePath);
4698 HeapFree(GetProcessHeap(),0,FileName);
4702 buffer = load_dynamic_stringW(row,5);
4704 build_icon_path(package,buffer,&(package->progids[index].IconPath));
4705 HeapFree(GetProcessHeap(),0,buffer);
4708 package->progids[index].CurVerIndex = -1;
4710 /* if we have a parent then we may be that parents CurVer */
4711 if (package->progids[index].ParentIndex >= 0)
4713 int pindex = package->progids[index].ParentIndex;
4714 while (package->progids[pindex].ParentIndex>= 0)
4715 pindex = package->progids[pindex].ParentIndex;
4717 FIXME("BAD BAD need to determing if we are really the CurVer\n");
4719 package->progids[index].CurVerIndex = pindex;
4725 static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid)
4731 static const WCHAR ExecSeqQuery[] =
4732 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4733 '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ',
4734 '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0};
4739 /* check for progids already loaded */
4740 for (i = 0; i < package->loaded_progids; i++)
4741 if (strcmpiW(package->progids[i].ProgID,progid)==0)
4743 TRACE("found progid %s at index %i\n",debugstr_w(progid), i);
4747 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, progid);
4748 if (rc != ERROR_SUCCESS)
4751 rc = MSI_ViewExecute(view, 0);
4752 if (rc != ERROR_SUCCESS)
4754 MSI_ViewClose(view);
4755 msiobj_release(&view->hdr);
4759 rc = MSI_ViewFetch(view,&row);
4760 if (rc != ERROR_SUCCESS)
4762 MSI_ViewClose(view);
4763 msiobj_release(&view->hdr);
4767 rc = load_progid(package, row);
4768 msiobj_release(&row->hdr);
4769 MSI_ViewClose(view);
4770 msiobj_release(&view->hdr);
4775 static INT load_class(MSIPACKAGE* package, MSIRECORD *row)
4777 DWORD index = package->loaded_classes;
4781 /* fill in the data */
4783 package->loaded_classes++;
4784 if (package->loaded_classes== 1)
4785 package->classes = HeapAlloc(GetProcessHeap(),0,sizeof(MSICLASS));
4787 package->classes = HeapReAlloc(GetProcessHeap(),0,
4788 package->classes, package->loaded_classes * sizeof(MSICLASS));
4790 memset(&package->classes[index],0,sizeof(MSICLASS));
4792 sz = IDENTIFIER_SIZE;
4793 MSI_RecordGetStringW(row, 1, package->classes[index].CLSID, &sz);
4794 TRACE("loading class %s\n",debugstr_w(package->classes[index].CLSID));
4795 sz = IDENTIFIER_SIZE;
4796 MSI_RecordGetStringW(row, 2, package->classes[index].Context, &sz);
4797 buffer = load_dynamic_stringW(row,3);
4798 package->classes[index].ComponentIndex = get_loaded_component(package,
4800 HeapFree(GetProcessHeap(),0,buffer);
4802 package->classes[index].ProgIDText = load_dynamic_stringW(row,4);
4803 package->classes[index].ProgIDIndex =
4804 load_given_progid(package, package->classes[index].ProgIDText);
4806 package->classes[index].Description = load_dynamic_stringW(row,5);
4808 buffer = load_dynamic_stringW(row,6);
4810 package->classes[index].AppIDIndex =
4811 load_given_appid(package, buffer);
4813 package->classes[index].AppIDIndex = -1;
4814 HeapFree(GetProcessHeap(),0,buffer);
4816 package->classes[index].FileTypeMask = load_dynamic_stringW(row,7);
4818 if (!MSI_RecordIsNull(row,9))
4821 INT icon_index = MSI_RecordGetInteger(row,9);
4822 LPWSTR FileName = load_dynamic_stringW(row,8);
4824 static const WCHAR fmt[] = {'%','s',',','%','i',0};
4826 build_icon_path(package,FileName,&FilePath);
4828 package->classes[index].IconPath =
4829 HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)*
4832 sprintfW(package->classes[index].IconPath,fmt,FilePath,icon_index);
4834 HeapFree(GetProcessHeap(),0,FilePath);
4835 HeapFree(GetProcessHeap(),0,FileName);
4839 buffer = load_dynamic_stringW(row,8);
4841 build_icon_path(package,buffer,&(package->classes[index].IconPath));
4842 HeapFree(GetProcessHeap(),0,buffer);
4845 if (!MSI_RecordIsNull(row,10))
4847 i = MSI_RecordGetInteger(row,10);
4848 if (i != MSI_NULL_INTEGER && i > 0 && i < 4)
4850 static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0};
4851 static const WCHAR ole32[] = {'o','l','e','3','2','.','d','l','l',0};
4856 package->classes[index].DefInprocHandler = strdupW(ole2);
4859 package->classes[index].DefInprocHandler32 = strdupW(ole32);
4862 package->classes[index].DefInprocHandler = strdupW(ole2);
4863 package->classes[index].DefInprocHandler32 = strdupW(ole32);
4869 package->classes[index].DefInprocHandler32 = load_dynamic_stringW(
4871 reduce_to_longfilename(package->classes[index].DefInprocHandler32);
4874 buffer = load_dynamic_stringW(row,11);
4875 deformat_string(package,buffer,&package->classes[index].Argument);
4876 HeapFree(GetProcessHeap(),0,buffer);
4878 buffer = load_dynamic_stringW(row,12);
4879 package->classes[index].FeatureIndex = get_loaded_feature(package,buffer);
4880 HeapFree(GetProcessHeap(),0,buffer);
4882 package->classes[index].Attributes = MSI_RecordGetInteger(row,13);
4888 * the Class table has 3 primary keys. Generally it is only
4889 * referenced through the first CLSID key. However when loading
4890 * all of the classes we need to make sure we do not ignore rows
4891 * with other Context and ComponentIndexs
4893 static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid)
4899 static const WCHAR ExecSeqQuery[] =
4900 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4901 '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ',
4902 '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0};
4908 /* check for classes already loaded */
4909 for (i = 0; i < package->loaded_classes; i++)
4910 if (strcmpiW(package->classes[i].CLSID,classid)==0)
4912 TRACE("found class %s at index %i\n",debugstr_w(classid), i);
4916 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, classid);
4917 if (rc != ERROR_SUCCESS)
4920 rc = MSI_ViewExecute(view, 0);
4921 if (rc != ERROR_SUCCESS)
4923 MSI_ViewClose(view);
4924 msiobj_release(&view->hdr);
4928 rc = MSI_ViewFetch(view,&row);
4929 if (rc != ERROR_SUCCESS)
4931 MSI_ViewClose(view);
4932 msiobj_release(&view->hdr);
4936 rc = load_class(package, row);
4937 msiobj_release(&row->hdr);
4938 MSI_ViewClose(view);
4939 msiobj_release(&view->hdr);
4944 static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension);
4946 static INT load_mime(MSIPACKAGE* package, MSIRECORD *row)
4948 DWORD index = package->loaded_mimes;
4952 /* fill in the data */
4954 package->loaded_mimes++;
4955 if (package->loaded_mimes== 1)
4956 package->mimes= HeapAlloc(GetProcessHeap(),0,sizeof(MSIMIME));
4958 package->mimes= HeapReAlloc(GetProcessHeap(),0,
4959 package->mimes, package->loaded_mimes*
4962 memset(&package->mimes[index],0,sizeof(MSIMIME));
4964 package->mimes[index].ContentType = load_dynamic_stringW(row,1);
4965 TRACE("loading mime %s\n",debugstr_w(package->mimes[index].ContentType));
4967 buffer = load_dynamic_stringW(row,2);
4968 package->mimes[index].ExtensionIndex = load_given_extension(package,
4970 HeapFree(GetProcessHeap(),0,buffer);
4972 sz = IDENTIFIER_SIZE;
4973 MSI_RecordGetStringW(row,3,package->mimes[index].CLSID,&sz);
4974 package->mimes[index].ClassIndex= load_given_class(package,
4975 package->mimes[index].CLSID);
4980 static INT load_given_mime(MSIPACKAGE *package, LPCWSTR mime)
4986 static const WCHAR ExecSeqQuery[] =
4987 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4988 '`','M','I','M','E','`',' ','W','H','E','R','E',' ',
4989 '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ',
4990 '\'','%','s','\'',0};
4995 /* check for mime already loaded */
4996 for (i = 0; i < package->loaded_mimes; i++)
4997 if (strcmpiW(package->mimes[i].ContentType,mime)==0)
4999 TRACE("found mime %s at index %i\n",debugstr_w(mime), i);
5003 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, mime);
5004 if (rc != ERROR_SUCCESS)
5007 rc = MSI_ViewExecute(view, 0);
5008 if (rc != ERROR_SUCCESS)
5010 MSI_ViewClose(view);
5011 msiobj_release(&view->hdr);
5015 rc = MSI_ViewFetch(view,&row);
5016 if (rc != ERROR_SUCCESS)
5018 MSI_ViewClose(view);
5019 msiobj_release(&view->hdr);
5023 rc = load_mime(package, row);
5024 msiobj_release(&row->hdr);
5025 MSI_ViewClose(view);
5026 msiobj_release(&view->hdr);
5031 static INT load_extension(MSIPACKAGE* package, MSIRECORD *row)
5033 DWORD index = package->loaded_extensions;
5037 /* fill in the data */
5039 package->loaded_extensions++;
5040 if (package->loaded_extensions == 1)
5041 package->extensions = HeapAlloc(GetProcessHeap(),0,sizeof(MSIEXTENSION));
5043 package->extensions = HeapReAlloc(GetProcessHeap(),0,
5044 package->extensions, package->loaded_extensions*
5045 sizeof(MSIEXTENSION));
5047 memset(&package->extensions[index],0,sizeof(MSIEXTENSION));
5050 MSI_RecordGetStringW(row,1,package->extensions[index].Extension,&sz);
5051 TRACE("loading extension %s\n",
5052 debugstr_w(package->extensions[index].Extension));
5054 buffer = load_dynamic_stringW(row,2);
5055 package->extensions[index].ComponentIndex =
5056 get_loaded_component(package,buffer);
5057 HeapFree(GetProcessHeap(),0,buffer);
5059 package->extensions[index].ProgIDText = load_dynamic_stringW(row,3);
5060 package->extensions[index].ProgIDIndex = load_given_progid(package,
5061 package->extensions[index].ProgIDText);
5063 buffer = load_dynamic_stringW(row,4);
5064 package->extensions[index].MIMEIndex = load_given_mime(package,buffer);
5065 HeapFree(GetProcessHeap(),0,buffer);
5067 buffer = load_dynamic_stringW(row,5);
5068 package->extensions[index].FeatureIndex =
5069 get_loaded_feature(package,buffer);
5070 HeapFree(GetProcessHeap(),0,buffer);
5076 * While the extension table has 2 primary keys, this function is only looking
5077 * at the Extension key which is what is referenced as a forign key
5079 static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension)
5085 static const WCHAR ExecSeqQuery[] =
5086 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5087 '`','E','x','t','e','n','s','i','o','n','`',' ',
5088 'W','H','E','R','E',' ',
5089 '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ',
5090 '\'','%','s','\'',0};
5095 /* check for extensions already loaded */
5096 for (i = 0; i < package->loaded_extensions; i++)
5097 if (strcmpiW(package->extensions[i].Extension,extension)==0)
5099 TRACE("extension %s already loaded at %i\n",debugstr_w(extension),
5104 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, extension);
5105 if (rc != ERROR_SUCCESS)
5108 rc = MSI_ViewExecute(view, 0);
5109 if (rc != ERROR_SUCCESS)
5111 MSI_ViewClose(view);
5112 msiobj_release(&view->hdr);
5116 rc = MSI_ViewFetch(view,&row);
5117 if (rc != ERROR_SUCCESS)
5119 MSI_ViewClose(view);
5120 msiobj_release(&view->hdr);
5124 rc = load_extension(package, row);
5125 msiobj_release(&row->hdr);
5126 MSI_ViewClose(view);
5127 msiobj_release(&view->hdr);
5132 static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
5134 MSIPACKAGE* package = (MSIPACKAGE*)param;
5135 DWORD index = package->loaded_verbs;
5138 /* fill in the data */
5140 package->loaded_verbs++;
5141 if (package->loaded_verbs == 1)
5142 package->verbs = HeapAlloc(GetProcessHeap(),0,sizeof(MSIVERB));
5144 package->verbs = HeapReAlloc(GetProcessHeap(),0,
5145 package->verbs , package->loaded_verbs * sizeof(MSIVERB));
5147 memset(&package->verbs[index],0,sizeof(MSIVERB));
5149 buffer = load_dynamic_stringW(row,1);
5150 package->verbs[index].ExtensionIndex = load_given_extension(package,buffer);
5151 if (package->verbs[index].ExtensionIndex < 0 && buffer)
5152 ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer));
5153 HeapFree(GetProcessHeap(),0,buffer);
5155 package->verbs[index].Verb = load_dynamic_stringW(row,2);
5156 TRACE("loading verb %s\n",debugstr_w(package->verbs[index].Verb));
5157 package->verbs[index].Sequence = MSI_RecordGetInteger(row,3);
5159 buffer = load_dynamic_stringW(row,4);
5160 deformat_string(package,buffer,&package->verbs[index].Command);
5161 HeapFree(GetProcessHeap(),0,buffer);
5163 buffer = load_dynamic_stringW(row,5);
5164 deformat_string(package,buffer,&package->verbs[index].Argument);
5165 HeapFree(GetProcessHeap(),0,buffer);
5167 /* assosiate the verb with the correct extension */
5168 if (package->verbs[index].ExtensionIndex >= 0)
5170 MSIEXTENSION* extension = &package->extensions[package->verbs[index].
5172 int count = extension->VerbCount;
5175 FIXME("Exceeding max verb count! Increase that limit!!!\n");
5178 extension->VerbCount++;
5179 extension->Verbs[count] = index;
5183 return ERROR_SUCCESS;
5186 static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param)
5191 INT component_index;
5192 MSIPACKAGE* package =(MSIPACKAGE*)param;
5196 clsid = load_dynamic_stringW(rec,1);
5197 context = load_dynamic_stringW(rec,2);
5198 buffer = load_dynamic_stringW(rec,3);
5199 component_index = get_loaded_component(package,buffer);
5201 for (i = 0; i < package->loaded_classes; i++)
5203 if (strcmpiW(clsid,package->classes[i].CLSID))
5205 if (strcmpW(context,package->classes[i].Context))
5207 if (component_index == package->classes[i].ComponentIndex)
5214 HeapFree(GetProcessHeap(),0,buffer);
5215 HeapFree(GetProcessHeap(),0,clsid);
5216 HeapFree(GetProcessHeap(),0,context);
5219 load_class(package, rec);
5221 return ERROR_SUCCESS;
5224 static VOID load_all_classes(MSIPACKAGE *package)
5226 UINT rc = ERROR_SUCCESS;
5229 static const WCHAR ExecSeqQuery[] =
5230 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
5231 '`','C','l','a','s','s','`',0};
5233 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5234 if (rc != ERROR_SUCCESS)
5237 rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package);
5238 msiobj_release(&view->hdr);
5241 static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param)
5245 INT component_index;
5246 MSIPACKAGE* package =(MSIPACKAGE*)param;
5250 extension = load_dynamic_stringW(rec,1);
5251 buffer = load_dynamic_stringW(rec,2);
5252 component_index = get_loaded_component(package,buffer);
5254 for (i = 0; i < package->loaded_extensions; i++)
5256 if (strcmpiW(extension,package->extensions[i].Extension))
5258 if (component_index == package->extensions[i].ComponentIndex)
5265 HeapFree(GetProcessHeap(),0,buffer);
5266 HeapFree(GetProcessHeap(),0,extension);
5269 load_extension(package, rec);
5271 return ERROR_SUCCESS;
5274 static VOID load_all_extensions(MSIPACKAGE *package)
5276 UINT rc = ERROR_SUCCESS;
5279 static const WCHAR ExecSeqQuery[] =
5280 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5281 '`','E','x','t','e','n','s','i','o','n','`',0};
5283 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5284 if (rc != ERROR_SUCCESS)
5287 rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package);
5288 msiobj_release(&view->hdr);
5291 static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param)
5294 MSIPACKAGE* package =(MSIPACKAGE*)param;
5296 buffer = load_dynamic_stringW(rec,1);
5297 load_given_progid(package,buffer);
5298 HeapFree(GetProcessHeap(),0,buffer);
5299 return ERROR_SUCCESS;
5302 static VOID load_all_progids(MSIPACKAGE *package)
5304 UINT rc = ERROR_SUCCESS;
5307 static const WCHAR ExecSeqQuery[] =
5308 {'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ',
5309 'F','R','O','M',' ', '`','P','r','o','g','I','d','`',0};
5311 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5312 if (rc != ERROR_SUCCESS)
5315 rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package);
5316 msiobj_release(&view->hdr);
5319 static VOID load_all_verbs(MSIPACKAGE *package)
5321 UINT rc = ERROR_SUCCESS;
5324 static const WCHAR ExecSeqQuery[] =
5325 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5326 '`','V','e','r','b','`',0};
5328 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5329 if (rc != ERROR_SUCCESS)
5332 rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package);
5333 msiobj_release(&view->hdr);
5336 static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param)
5339 MSIPACKAGE* package =(MSIPACKAGE*)param;
5341 buffer = load_dynamic_stringW(rec,1);
5342 load_given_mime(package,buffer);
5343 HeapFree(GetProcessHeap(),0,buffer);
5344 return ERROR_SUCCESS;
5347 static VOID load_all_mimes(MSIPACKAGE *package)
5349 UINT rc = ERROR_SUCCESS;
5352 static const WCHAR ExecSeqQuery[] =
5353 {'S','E','L','E','C','T',' ',
5354 '`','C','o','n','t','e','n','t','T','y','p','e','`',
5355 ' ','F','R','O','M',' ',
5356 '`','M','I','M','E','`',0};
5358 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5359 if (rc != ERROR_SUCCESS)
5362 rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package);
5363 msiobj_release(&view->hdr);
5366 static void load_classes_and_such(MSIPACKAGE *package)
5368 TRACE("Loading all the class info and related tables\n");
5370 /* check if already loaded */
5371 if (package->classes || package->extensions || package->progids ||
5372 package->verbs || package->mimes)
5375 load_all_classes(package);
5376 load_all_extensions(package);
5377 load_all_progids(package);
5378 /* these loads must come after the other loads */
5379 load_all_verbs(package);
5380 load_all_mimes(package);
5383 static void mark_progid_for_install(MSIPACKAGE* package, INT index)
5388 if (index < 0 || index >= package->loaded_progids)
5391 progid = &package->progids[index];
5393 if (progid->InstallMe == TRUE)
5396 progid->InstallMe = TRUE;
5398 /* all children if this is a parent also install */
5399 for (i = 0; i < package->loaded_progids; i++)
5400 if (package->progids[i].ParentIndex == index)
5401 mark_progid_for_install(package,i);
5404 static void mark_mime_for_install(MSIPACKAGE* package, INT index)
5408 if (index < 0 || index >= package->loaded_mimes)
5411 mime = &package->mimes[index];
5413 if (mime->InstallMe == TRUE)
5416 mime->InstallMe = TRUE;
5419 static UINT register_appid(MSIPACKAGE *package, int appidIndex, LPCWSTR app )
5421 static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
5425 return ERROR_INVALID_HANDLE;
5427 RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
5428 RegCreateKeyW(hkey2,package->appids[appidIndex].AppID,&hkey3);
5429 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
5430 (strlenW(app)+1)*sizeof(WCHAR));
5432 if (package->appids[appidIndex].RemoteServerName)
5435 static const WCHAR szRemoteServerName[] =
5436 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',
5439 size = (strlenW(package->appids[appidIndex].RemoteServerName)+1) *
5442 RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,
5443 (LPVOID)package->appids[appidIndex].RemoteServerName,
5447 if (package->appids[appidIndex].LocalServer)
5449 static const WCHAR szLocalService[] =
5450 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
5452 size = (strlenW(package->appids[appidIndex].LocalServer)+1) *
5455 RegSetValueExW(hkey3,szLocalService,0,REG_SZ,
5456 (LPVOID)package->appids[appidIndex].LocalServer,size);
5459 if (package->appids[appidIndex].ServiceParameters)
5461 static const WCHAR szService[] =
5462 {'S','e','r','v','i','c','e',
5463 'P','a','r','a','m','e','t','e','r','s',0};
5465 size = (strlenW(package->appids[appidIndex].ServiceParameters)+1) *
5467 RegSetValueExW(hkey3,szService,0,REG_SZ,
5468 (LPVOID)package->appids[appidIndex].ServiceParameters,
5472 if (package->appids[appidIndex].DllSurrogate)
5474 static const WCHAR szDLL[] =
5475 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
5477 size = (strlenW(package->appids[appidIndex].DllSurrogate)+1) *
5479 RegSetValueExW(hkey3,szDLL,0,REG_SZ,
5480 (LPVOID)package->appids[appidIndex].DllSurrogate,size);
5483 if (package->appids[appidIndex].ActivateAtStorage)
5485 static const WCHAR szActivate[] =
5486 {'A','c','t','i','v','a','t','e','A','s',
5487 'S','t','o','r','a','g','e',0};
5488 static const WCHAR szY[] = {'Y',0};
5490 RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
5493 if (package->appids[appidIndex].RunAsInteractiveUser)
5495 static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
5496 static const WCHAR szUser[] =
5497 {'I','n','t','e','r','a','c','t','i','v','e',' ',
5500 RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,sizeof(szUser));
5505 return ERROR_SUCCESS;
5508 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
5511 * Again I am assuming the words, "Whose key file represents" when referring
5512 * to a Component as to meaning that Components KeyPath file
5517 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
5518 static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
5519 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 };
5520 static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
5521 static const WCHAR szSpace[] = {' ',0};
5522 HKEY hkey,hkey2,hkey3;
5526 return ERROR_INVALID_HANDLE;
5528 load_classes_and_such(package);
5529 rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
5530 if (rc != ERROR_SUCCESS)
5531 return ERROR_FUNCTION_FAILED;
5533 for (i = 0; i < package->loaded_classes; i++)
5539 if (package->classes[i].ComponentIndex < 0)
5544 index = package->classes[i].ComponentIndex;
5545 f_index = package->classes[i].FeatureIndex;
5548 * yes. MSDN says that these are based on _Feature_ not on
5549 * Component. So verify the feature is to be installed
5551 if ((!ACTION_VerifyFeatureForAction(package, f_index,
5552 INSTALLSTATE_LOCAL)) &&
5553 (!ACTION_VerifyFeatureForAction(package, f_index,
5554 INSTALLSTATE_ADVERTISED)))
5556 TRACE("Skipping class %s reg due to disabled feature %s\n",
5557 debugstr_w(package->classes[i].CLSID),
5558 debugstr_w(package->features[f_index].Feature));
5563 TRACE("Registering index %i class %s\n",i,
5564 debugstr_w(package->classes[i].CLSID));
5566 package->classes[i].Installed = TRUE;
5567 if (package->classes[i].ProgIDIndex >= 0)
5568 mark_progid_for_install(package, package->classes[i].ProgIDIndex);
5570 RegCreateKeyW(hkey,package->classes[i].CLSID,&hkey2);
5572 if (package->classes[i].Description)
5573 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)package->classes[i].
5574 Description, (strlenW(package->classes[i].
5575 Description)+1)*sizeof(WCHAR));
5577 RegCreateKeyW(hkey2,package->classes[i].Context,&hkey3);
5578 index = get_loaded_file(package,package->components[index].KeyPath);
5581 /* the context server is a short path name */
5583 sz = GetShortPathNameW(package->files[index].TargetPath, NULL, 0);
5586 ERR("Unable to find short path for CLSID COM Server\n");
5590 size = sz * sizeof(WCHAR);
5592 if (package->classes[i].Argument)
5594 size += strlenW(package->classes[i].Argument) * sizeof(WCHAR);
5595 size += sizeof(WCHAR);
5598 argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
5599 GetShortPathNameW(package->files[index].TargetPath, argument, sz);
5601 if (package->classes[i].Argument)
5603 strcatW(argument,szSpace);
5604 strcatW(argument,package->classes[i].Argument);
5607 RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
5608 HeapFree(GetProcessHeap(),0,argument);
5613 if (package->classes[i].ProgIDIndex >= 0 ||
5614 package->classes[i].ProgIDText)
5618 if (package->classes[i].ProgIDIndex >= 0)
5619 progid = package->progids[
5620 package->classes[i].ProgIDIndex].ProgID;
5622 progid = package->classes[i].ProgIDText;
5624 RegCreateKeyW(hkey2,szProgID,&hkey3);
5625 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)progid,
5626 (strlenW(progid)+1) *sizeof(WCHAR));
5629 if (package->classes[i].ProgIDIndex >= 0 &&
5630 package->progids[package->classes[i].ProgIDIndex].ParentIndex
5633 progid = package->progids[package->progids[
5634 package->classes[i].ProgIDIndex].ParentIndex].ProgID;
5636 RegCreateKeyW(hkey2,szVIProgID,&hkey3);
5637 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)progid,
5638 (strlenW(progid)+1) *sizeof(WCHAR));
5643 if (package->classes[i].AppIDIndex >= 0)
5645 RegSetValueExW(hkey2,szAppID,0,REG_SZ,
5646 (LPVOID)package->appids[package->classes[i].AppIDIndex].AppID,
5647 (strlenW(package->appids[package->classes[i].AppIDIndex].AppID)+1)
5650 register_appid(package,package->classes[i].AppIDIndex,
5651 package->classes[i].Description);
5654 if (package->classes[i].FileTypeMask)
5656 FIXME("Process field 7\n");
5659 if (package->classes[i].IconPath)
5661 static const WCHAR szDefaultIcon[] =
5662 {'D','e','f','a','u','l','t','I','c','o','n',0};
5664 RegCreateKeyW(hkey2,szDefaultIcon,&hkey3);
5666 RegSetValueExW(hkey3,NULL,0,REG_SZ,
5667 (LPVOID)package->classes[i].IconPath,
5668 (strlenW(package->classes[i].IconPath)+1) *
5674 if (package->classes[i].DefInprocHandler)
5676 static const WCHAR szInproc[] =
5677 {'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
5679 size = (strlenW(package->classes[i].DefInprocHandler) + 1) *
5681 RegCreateKeyW(hkey2,szInproc,&hkey3);
5682 RegSetValueExW(hkey3,NULL,0,REG_SZ,
5683 (LPVOID)package->classes[i].DefInprocHandler, size);
5687 if (package->classes[i].DefInprocHandler32)
5689 static const WCHAR szInproc32[] =
5690 {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',
5692 size = (strlenW(package->classes[i].DefInprocHandler32) + 1) *
5695 RegCreateKeyW(hkey2,szInproc32,&hkey3);
5696 RegSetValueExW(hkey3,NULL,0,REG_SZ,
5697 (LPVOID)package->classes[i].DefInprocHandler32,size);
5703 uirow = MSI_CreateRecord(1);
5705 MSI_RecordSetStringW(uirow,1,package->classes[i].CLSID);
5706 ui_actiondata(package,szRegisterClassInfo,uirow);
5707 msiobj_release(&uirow->hdr);
5714 static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid,
5717 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
5718 static const WCHAR szDefaultIcon[] =
5719 {'D','e','f','a','u','l','t','I','c','o','n',0};
5722 RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey);
5724 if (progid->Description)
5726 RegSetValueExW(hkey,NULL,0,REG_SZ,
5727 (LPVOID)progid->Description,
5728 (strlenW(progid->Description)+1) *
5732 if (progid->ClassIndex >= 0)
5734 RegCreateKeyW(hkey,szCLSID,&hkey2);
5735 RegSetValueExW(hkey2,NULL,0,REG_SZ,
5736 (LPVOID)package->classes[progid->ClassIndex].CLSID,
5737 (strlenW(package->classes[progid->ClassIndex].CLSID)+1)
5741 strcpyW(clsid,package->classes[progid->ClassIndex].CLSID);
5747 FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
5750 if (progid->IconPath)
5752 RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
5754 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
5755 (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
5758 return ERROR_SUCCESS;
5761 static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid,
5764 UINT rc = ERROR_SUCCESS;
5766 if (progid->ParentIndex < 0)
5767 rc = register_progid_base(package, progid, clsid);
5772 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
5773 static const WCHAR szDefaultIcon[] =
5774 {'D','e','f','a','u','l','t','I','c','o','n',0};
5775 static const WCHAR szCurVer[] =
5776 {'C','u','r','V','e','r',0};
5778 /* check if already registered */
5779 RegCreateKeyExW(HKEY_CLASSES_ROOT, progid->ProgID, 0, NULL, 0,
5780 KEY_ALL_ACCESS, NULL, &hkey, &disp );
5781 if (disp == REG_OPENED_EXISTING_KEY)
5783 TRACE("Key already registered\n");
5788 TRACE("Registering Parent %s index %i\n",
5789 debugstr_w(package->progids[progid->ParentIndex].ProgID),
5790 progid->ParentIndex);
5791 rc = register_progid(package,&package->progids[progid->ParentIndex],
5794 /* clsid is same as parent */
5795 RegCreateKeyW(hkey,szCLSID,&hkey2);
5796 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
5802 if (progid->Description)
5804 RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid->Description,
5805 (strlenW(progid->Description)+1) * sizeof(WCHAR));
5808 if (progid->IconPath)
5810 RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
5811 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
5812 (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
5816 /* write out the current version */
5817 if (progid->CurVerIndex >= 0)
5819 RegCreateKeyW(hkey,szCurVer,&hkey2);
5820 RegSetValueExW(hkey2,NULL,0,REG_SZ,
5821 (LPVOID)package->progids[progid->CurVerIndex].ProgID,
5822 (strlenW(package->progids[progid->CurVerIndex].ProgID)+1) *
5832 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
5838 return ERROR_INVALID_HANDLE;
5840 load_classes_and_such(package);
5842 for (i = 0; i < package->loaded_progids; i++)
5844 WCHAR clsid[0x1000];
5846 /* check if this progid is to be installed */
5848 if (!package->progids[i].InstallMe)
5850 TRACE("progid %s not scheduled to be installed\n",
5851 debugstr_w(package->progids[i].ProgID));
5855 TRACE("Registering progid %s index %i\n",
5856 debugstr_w(package->progids[i].ProgID), i);
5858 register_progid(package,&package->progids[i],clsid);
5860 uirow = MSI_CreateRecord(1);
5861 MSI_RecordSetStringW(uirow,1,package->progids[i].ProgID);
5862 ui_actiondata(package,szRegisterProgIdInfo,uirow);
5863 msiobj_release(&uirow->hdr);
5866 return ERROR_SUCCESS;
5869 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name,
5873 LPWSTR SystemFolder;
5877 static const WCHAR szInstaller[] =
5878 {'M','i','c','r','o','s','o','f','t','\\',
5879 'I','n','s','t','a','l','l','e','r','\\',0};
5880 static const WCHAR szFolder[] =
5881 {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
5883 ProductCode = load_dynamic_property(package,szProductCode,&rc);
5887 SystemFolder = load_dynamic_property(package,szFolder,NULL);
5889 dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);
5891 create_full_pathW(dest);
5893 *FilePath = build_directory_name(2, dest, icon_name);
5895 HeapFree(GetProcessHeap(),0,SystemFolder);
5896 HeapFree(GetProcessHeap(),0,ProductCode);
5897 HeapFree(GetProcessHeap(),0,dest);
5898 return ERROR_SUCCESS;
5901 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
5905 MSIRECORD * row = 0;
5906 static const WCHAR Query[] =
5907 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5908 '`','S','h','o','r','t','c','u','t','`',0};
5914 return ERROR_INVALID_HANDLE;
5916 res = CoInitialize( NULL );
5919 ERR("CoInitialize failed\n");
5920 return ERROR_FUNCTION_FAILED;
5923 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
5924 if (rc != ERROR_SUCCESS)
5925 return ERROR_SUCCESS;
5927 rc = MSI_ViewExecute(view, 0);
5928 if (rc != ERROR_SUCCESS)
5930 MSI_ViewClose(view);
5931 msiobj_release(&view->hdr);
5937 LPWSTR target_file, target_folder;
5938 WCHAR buffer[0x100];
5941 static const WCHAR szlnk[]={'.','l','n','k',0};
5943 rc = MSI_ViewFetch(view,&row);
5944 if (rc != ERROR_SUCCESS)
5951 MSI_RecordGetStringW(row,4,buffer,&sz);
5953 index = get_loaded_component(package,buffer);
5957 msiobj_release(&row->hdr);
5961 if (!ACTION_VerifyComponentForAction(package, index,
5962 INSTALLSTATE_LOCAL))
5964 TRACE("Skipping shortcut creation due to disabled component\n");
5965 msiobj_release(&row->hdr);
5967 package->components[index].Action =
5968 package->components[index].Installed;
5973 package->components[index].Action = INSTALLSTATE_LOCAL;
5975 ui_actiondata(package,szCreateShortcuts,row);
5977 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
5978 &IID_IShellLinkW, (LPVOID *) &sl );
5982 ERR("Is IID_IShellLink\n");
5983 msiobj_release(&row->hdr);
5987 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
5990 ERR("Is IID_IPersistFile\n");
5991 msiobj_release(&row->hdr);
5996 MSI_RecordGetStringW(row,2,buffer,&sz);
5997 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
5999 /* may be needed because of a bug somehwere else */
6000 create_full_pathW(target_folder);
6003 MSI_RecordGetStringW(row,3,buffer,&sz);
6004 reduce_to_longfilename(buffer);
6005 if (!strchrW(buffer,'.') || strcmpiW(strchrW(buffer,'.'),szlnk))
6006 strcatW(buffer,szlnk);
6007 target_file = build_directory_name(2, target_folder, buffer);
6008 HeapFree(GetProcessHeap(),0,target_folder);
6011 MSI_RecordGetStringW(row,5,buffer,&sz);
6012 if (strchrW(buffer,'['))
6015 deformat_string(package,buffer,&deformated);
6016 IShellLinkW_SetPath(sl,deformated);
6017 HeapFree(GetProcessHeap(),0,deformated);
6022 FIXME("poorly handled shortcut format, advertised shortcut\n");
6023 keypath = strdupW(package->components[index].FullKeypath);
6024 IShellLinkW_SetPath(sl,keypath);
6025 HeapFree(GetProcessHeap(),0,keypath);
6028 if (!MSI_RecordIsNull(row,6))
6032 MSI_RecordGetStringW(row,6,buffer,&sz);
6033 deformat_string(package,buffer,&deformated);
6034 IShellLinkW_SetArguments(sl,deformated);
6035 HeapFree(GetProcessHeap(),0,deformated);
6038 if (!MSI_RecordIsNull(row,7))
6041 deformated = load_dynamic_stringW(row,7);
6042 IShellLinkW_SetDescription(sl,deformated);
6043 HeapFree(GetProcessHeap(),0,deformated);
6046 if (!MSI_RecordIsNull(row,8))
6047 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
6049 if (!MSI_RecordIsNull(row,9))
6055 MSI_RecordGetStringW(row,9,buffer,&sz);
6057 build_icon_path(package,buffer,&Path);
6058 index = MSI_RecordGetInteger(row,10);
6060 IShellLinkW_SetIconLocation(sl,Path,index);
6061 HeapFree(GetProcessHeap(),0,Path);
6064 if (!MSI_RecordIsNull(row,11))
6065 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
6067 if (!MSI_RecordIsNull(row,12))
6071 MSI_RecordGetStringW(row,12,buffer,&sz);
6072 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
6073 IShellLinkW_SetWorkingDirectory(sl,Path);
6074 HeapFree(GetProcessHeap(), 0, Path);
6077 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
6078 IPersistFile_Save(pf,target_file,FALSE);
6080 HeapFree(GetProcessHeap(),0,target_file);
6082 IPersistFile_Release( pf );
6083 IShellLinkW_Release( sl );
6085 msiobj_release(&row->hdr);
6087 MSI_ViewClose(view);
6088 msiobj_release(&view->hdr);
6098 * 99% of the work done here is only done for
6099 * advertised installs. However this is where the
6100 * Icon table is processed and written out
6101 * so that is what I am going to do here.
6103 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
6107 MSIRECORD * row = 0;
6108 static const WCHAR Query[]=
6109 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6110 '`','I','c','o','n','`',0};
6112 /* for registry stuff */
6116 static const WCHAR szProductName[] =
6117 {'P','r','o','d','u','c','t','N','a','m','e',0};
6118 static const WCHAR szPackageCode[] =
6119 {'P','a','c','k','a','g','e','C','o','d','e',0};
6122 MSIHANDLE hDb, hSumInfo;
6125 return ERROR_INVALID_HANDLE;
6127 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
6128 if (rc != ERROR_SUCCESS)
6131 rc = MSI_ViewExecute(view, 0);
6132 if (rc != ERROR_SUCCESS)
6134 MSI_ViewClose(view);
6135 msiobj_release(&view->hdr);
6142 WCHAR *FilePath=NULL;
6143 WCHAR *FileName=NULL;
6146 rc = MSI_ViewFetch(view,&row);
6147 if (rc != ERROR_SUCCESS)
6153 FileName = load_dynamic_stringW(row,1);
6156 ERR("Unable to get FileName\n");
6157 msiobj_release(&row->hdr);
6161 build_icon_path(package,FileName,&FilePath);
6163 HeapFree(GetProcessHeap(),0,FileName);
6165 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
6167 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
6168 FILE_ATTRIBUTE_NORMAL, NULL);
6170 if (the_file == INVALID_HANDLE_VALUE)
6172 ERR("Unable to create file %s\n",debugstr_w(FilePath));
6173 msiobj_release(&row->hdr);
6174 HeapFree(GetProcessHeap(),0,FilePath);
6182 rc = MSI_RecordReadStream(row,2,buffer,&sz);
6183 if (rc != ERROR_SUCCESS)
6185 ERR("Failed to get stream\n");
6186 CloseHandle(the_file);
6187 DeleteFileW(FilePath);
6190 WriteFile(the_file,buffer,sz,&write,NULL);
6191 } while (sz == 1024);
6193 HeapFree(GetProcessHeap(),0,FilePath);
6195 CloseHandle(the_file);
6196 msiobj_release(&row->hdr);
6198 MSI_ViewClose(view);
6199 msiobj_release(&view->hdr);
6202 /* ok there is a lot more done here but i need to figure out what */
6203 productcode = load_dynamic_property(package,szProductCode,&rc);
6207 rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE);
6208 if (rc != ERROR_SUCCESS)
6211 rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
6212 if (rc != ERROR_SUCCESS)
6216 buffer = load_dynamic_property(package,szProductName,NULL);
6217 size = strlenW(buffer)*sizeof(WCHAR);
6218 RegSetValueExW(hukey,szProductName,0,REG_SZ, (LPSTR)buffer,size);
6219 HeapFree(GetProcessHeap(),0,buffer);
6220 FIXME("Need to write more keys to the user registry\n");
6222 hDb= alloc_msihandle( &package->db->hdr );
6223 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
6224 MsiCloseHandle(hDb);
6225 if (rc == ERROR_SUCCESS)
6227 WCHAR guidbuffer[0x200];
6229 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
6231 if (rc == ERROR_SUCCESS)
6233 WCHAR squashed[GUID_SIZE];
6234 /* for now we only care about the first guid */
6235 LPWSTR ptr = strchrW(guidbuffer,';');
6237 squash_guid(guidbuffer,squashed);
6238 size = strlenW(squashed)*sizeof(WCHAR);
6239 RegSetValueExW(hukey,szPackageCode,0,REG_SZ, (LPSTR)squashed,
6244 ERR("Unable to query Revision_Number... \n");
6247 MsiCloseHandle(hSumInfo);
6251 ERR("Unable to open Summary Information\n");
6257 HeapFree(GetProcessHeap(),0,productcode);
6264 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
6268 MSIRECORD * row = 0;
6269 static const WCHAR ExecSeqQuery[] =
6270 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6271 '`','I','n','i','F','i','l','e','`',0};
6272 static const WCHAR szWindowsFolder[] =
6273 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
6275 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6276 if (rc != ERROR_SUCCESS)
6278 TRACE("no IniFile table\n");
6279 return ERROR_SUCCESS;
6282 rc = MSI_ViewExecute(view, 0);
6283 if (rc != ERROR_SUCCESS)
6285 MSI_ViewClose(view);
6286 msiobj_release(&view->hdr);
6292 LPWSTR component,filename,dirproperty,section,key,value,identifier;
6293 LPWSTR deformated_section, deformated_key, deformated_value;
6294 LPWSTR folder, fullname = NULL;
6296 INT component_index,action;
6298 rc = MSI_ViewFetch(view,&row);
6299 if (rc != ERROR_SUCCESS)
6305 component = load_dynamic_stringW(row, 8);
6306 component_index = get_loaded_component(package,component);
6307 HeapFree(GetProcessHeap(),0,component);
6309 if (!ACTION_VerifyComponentForAction(package, component_index,
6310 INSTALLSTATE_LOCAL))
6312 TRACE("Skipping ini file due to disabled component\n");
6313 msiobj_release(&row->hdr);
6315 package->components[component_index].Action =
6316 package->components[component_index].Installed;
6321 package->components[component_index].Action = INSTALLSTATE_LOCAL;
6323 identifier = load_dynamic_stringW(row,1);
6324 filename = load_dynamic_stringW(row,2);
6325 dirproperty = load_dynamic_stringW(row,3);
6326 section = load_dynamic_stringW(row,4);
6327 key = load_dynamic_stringW(row,5);
6328 value = load_dynamic_stringW(row,6);
6329 action = MSI_RecordGetInteger(row,7);
6331 deformat_string(package,section,&deformated_section);
6332 deformat_string(package,key,&deformated_key);
6333 deformat_string(package,value,&deformated_value);
6337 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
6339 folder = load_dynamic_property(package,dirproperty,NULL);
6342 folder = load_dynamic_property(package, szWindowsFolder, NULL);
6346 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
6350 fullname = build_directory_name(3, folder, filename, NULL);
6354 TRACE("Adding value %s to section %s in %s\n",
6355 debugstr_w(deformated_key), debugstr_w(deformated_section),
6356 debugstr_w(fullname));
6357 WritePrivateProfileStringW(deformated_section, deformated_key,
6358 deformated_value, fullname);
6360 else if (action == 1)
6363 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
6364 returned, 10, fullname);
6365 if (returned[0] == 0)
6367 TRACE("Adding value %s to section %s in %s\n",
6368 debugstr_w(deformated_key), debugstr_w(deformated_section),
6369 debugstr_w(fullname));
6371 WritePrivateProfileStringW(deformated_section, deformated_key,
6372 deformated_value, fullname);
6375 else if (action == 3)
6377 FIXME("Append to existing section not yet implemented\n");
6380 uirow = MSI_CreateRecord(4);
6381 MSI_RecordSetStringW(uirow,1,identifier);
6382 MSI_RecordSetStringW(uirow,2,deformated_section);
6383 MSI_RecordSetStringW(uirow,3,deformated_key);
6384 MSI_RecordSetStringW(uirow,4,deformated_value);
6385 ui_actiondata(package,szWriteIniValues,uirow);
6386 msiobj_release( &uirow->hdr );
6388 HeapFree(GetProcessHeap(),0,identifier);
6389 HeapFree(GetProcessHeap(),0,fullname);
6390 HeapFree(GetProcessHeap(),0,filename);
6391 HeapFree(GetProcessHeap(),0,key);
6392 HeapFree(GetProcessHeap(),0,value);
6393 HeapFree(GetProcessHeap(),0,section);
6394 HeapFree(GetProcessHeap(),0,dirproperty);
6395 HeapFree(GetProcessHeap(),0,folder);
6396 HeapFree(GetProcessHeap(),0,deformated_key);
6397 HeapFree(GetProcessHeap(),0,deformated_value);
6398 HeapFree(GetProcessHeap(),0,deformated_section);
6399 msiobj_release(&row->hdr);
6401 MSI_ViewClose(view);
6402 msiobj_release(&view->hdr);
6406 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
6410 MSIRECORD * row = 0;
6411 static const WCHAR ExecSeqQuery[] =
6412 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6413 '`','S','e','l','f','R','e','g','`',0};
6415 static const WCHAR ExeStr[] =
6416 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
6417 static const WCHAR close[] = {'\"',0};
6419 PROCESS_INFORMATION info;
6422 memset(&si,0,sizeof(STARTUPINFOW));
6424 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6425 if (rc != ERROR_SUCCESS)
6427 TRACE("no SelfReg table\n");
6428 return ERROR_SUCCESS;
6431 rc = MSI_ViewExecute(view, 0);
6432 if (rc != ERROR_SUCCESS)
6434 MSI_ViewClose(view);
6435 msiobj_release(&view->hdr);
6445 rc = MSI_ViewFetch(view,&row);
6446 if (rc != ERROR_SUCCESS)
6452 filename = load_dynamic_stringW(row,1);
6453 index = get_loaded_file(package,filename);
6457 ERR("Unable to find file id %s\n",debugstr_w(filename));
6458 HeapFree(GetProcessHeap(),0,filename);
6459 msiobj_release(&row->hdr);
6462 HeapFree(GetProcessHeap(),0,filename);
6464 len = strlenW(ExeStr);
6465 len += strlenW(package->files[index].TargetPath);
6468 filename = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
6469 strcpyW(filename,ExeStr);
6470 strcatW(filename,package->files[index].TargetPath);
6471 strcatW(filename,close);
6473 TRACE("Registering %s\n",debugstr_w(filename));
6474 brc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL,
6475 c_colon, &si, &info);
6478 msi_dialog_check_messages(info.hProcess);
6480 HeapFree(GetProcessHeap(),0,filename);
6481 msiobj_release(&row->hdr);
6483 MSI_ViewClose(view);
6484 msiobj_release(&view->hdr);
6488 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
6497 return ERROR_INVALID_HANDLE;
6499 productcode = load_dynamic_property(package,szProductCode,&rc);
6503 rc = MSIREG_OpenFeaturesKey(productcode,&hkey,TRUE);
6504 if (rc != ERROR_SUCCESS)
6507 rc = MSIREG_OpenUserFeaturesKey(productcode,&hukey,TRUE);
6508 if (rc != ERROR_SUCCESS)
6511 /* here the guids are base 85 encoded */
6512 for (i = 0; i < package->loaded_features; i++)
6518 BOOL absent = FALSE;
6520 if (!ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_LOCAL) &&
6521 !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_SOURCE) &&
6522 !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_ADVERTISED))
6525 size = package->features[i].ComponentCount*21;
6527 if (package->features[i].Feature_Parent[0])
6528 size += strlenW(package->features[i].Feature_Parent)+2;
6530 data = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
6533 for (j = 0; j < package->features[i].ComponentCount; j++)
6536 memset(buf,0,sizeof(buf));
6537 if (package->components
6538 [package->features[i].Components[j]].ComponentId[0]!=0)
6540 TRACE("From %s\n",debugstr_w(package->components
6541 [package->features[i].Components[j]].ComponentId));
6542 CLSIDFromString(package->components
6543 [package->features[i].Components[j]].ComponentId,
6545 encode_base85_guid(&clsid,buf);
6546 TRACE("to %s\n",debugstr_w(buf));
6550 if (package->features[i].Feature_Parent[0])
6552 static const WCHAR sep[] = {'\2',0};
6554 strcatW(data,package->features[i].Feature_Parent);
6557 size = (strlenW(data)+1)*sizeof(WCHAR);
6558 RegSetValueExW(hkey,package->features[i].Feature,0,REG_SZ,
6560 HeapFree(GetProcessHeap(),0,data);
6564 size = strlenW(package->features[i].Feature_Parent)*sizeof(WCHAR);
6565 RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,
6566 (LPSTR)package->features[i].Feature_Parent,size);
6570 size = (strlenW(package->features[i].Feature_Parent)+2)*
6572 data = HeapAlloc(GetProcessHeap(),0,size);
6574 strcpyW(&data[1],package->features[i].Feature_Parent);
6575 RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,
6577 HeapFree(GetProcessHeap(),0,data);
6584 HeapFree(GetProcessHeap(), 0, productcode);
6588 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
6595 static WCHAR szNONE[] = {0};
6596 static const WCHAR szWindowsInstaler[] =
6597 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
6598 static const WCHAR szPropKeys[][80] =
6600 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0},
6601 {'A','R','P','C','O','N','T','A','C','T',0},
6602 {'A','R','P','C','O','M','M','E','N','T','S',0},
6603 {'P','r','o','d','u','c','t','N','a','m','e',0},
6604 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0},
6605 {'A','R','P','H','E','L','P','L','I','N','K',0},
6606 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0},
6607 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0},
6608 {'S','o','u','r','c','e','D','i','r',0},
6609 {'M','a','n','u','f','a','c','t','u','r','e','r',0},
6610 {'A','R','P','R','E','A','D','M','E',0},
6611 {'A','R','P','S','I','Z','E',0},
6612 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0},
6613 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0},
6617 static const WCHAR szRegKeys[][80] =
6619 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0},
6620 {'C','o','n','t','a','c','t',0},
6621 {'C','o','m','m','e','n','t','s',0},
6622 {'D','i','s','p','l','a','y','N','a','m','e',0},
6623 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0},
6624 {'H','e','l','p','L','i','n','k',0},
6625 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0},
6626 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0},
6627 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0},
6628 {'P','u','b','l','i','s','h','e','r',0},
6629 {'R','e','a','d','m','e',0},
6630 {'S','i','z','e',0},
6631 {'U','R','L','I','n','f','o','A','b','o','u','t',0},
6632 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0},
6636 static const WCHAR installerPathFmt[] = {
6638 'I','n','s','t','a','l','l','e','r','\\',0};
6639 static const WCHAR fmt[] = {
6641 'I','n','s','t','a','l','l','e','r','\\',
6642 '%','x','.','m','s','i',0};
6643 static const WCHAR szLocalPackage[]=
6644 {'L','o','c','a','l','P','a','c','k','a','g','e',0};
6645 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
6649 return ERROR_INVALID_HANDLE;
6651 productcode = load_dynamic_property(package,szProductCode,&rc);
6655 rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
6656 if (rc != ERROR_SUCCESS)
6659 /* dump all the info i can grab */
6660 FIXME("Flesh out more information \n");
6663 while (szPropKeys[i][0]!=0)
6665 buffer = load_dynamic_property(package,szPropKeys[i],&rc);
6666 if (rc != ERROR_SUCCESS)
6668 size = strlenW(buffer)*sizeof(WCHAR);
6669 RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);
6675 RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPSTR)&rc,size);
6677 /* copy the package locally */
6678 num = GetTickCount() & 0xffff;
6682 GetWindowsDirectoryW(windir, sizeof(windir) / sizeof(windir[0]));
6683 snprintfW(packagefile,sizeof(packagefile)/sizeof(packagefile[0]),fmt,
6687 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
6688 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
6689 if (handle != INVALID_HANDLE_VALUE)
6691 CloseHandle(handle);
6694 if (GetLastError() != ERROR_FILE_EXISTS &&
6695 GetLastError() != ERROR_SHARING_VIOLATION)
6697 if (!(++num & 0xffff)) num = 1;
6698 sprintfW(packagefile,fmt,num);
6699 } while (num != start);
6701 snprintfW(path,sizeof(path)/sizeof(path[0]),installerPathFmt,windir);
6702 create_full_pathW(path);
6703 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
6704 if (!CopyFileW(package->PackagePath,packagefile,FALSE))
6705 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
6706 debugstr_w(package->PackagePath), debugstr_w(packagefile),
6708 size = strlenW(packagefile)*sizeof(WCHAR);
6709 RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size);
6712 HeapFree(GetProcessHeap(),0,productcode);
6715 return ERROR_SUCCESS;
6718 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
6723 return ERROR_INVALID_HANDLE;
6725 rc = execute_script(package,INSTALL_SCRIPT);
6730 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
6735 return ERROR_INVALID_HANDLE;
6737 /* turn off scheduleing */
6738 package->script->CurrentlyScripting= FALSE;
6740 /* first do the same as an InstallExecute */
6741 rc = ACTION_InstallExecute(package);
6742 if (rc != ERROR_SUCCESS)
6745 /* then handle Commit Actions */
6746 rc = execute_script(package,COMMIT_SCRIPT);
6751 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
6753 static const WCHAR RunOnce[] = {
6754 'S','o','f','t','w','a','r','e','\\',
6755 'M','i','c','r','o','s','o','f','t','\\',
6756 'W','i','n','d','o','w','s','\\',
6757 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
6758 'R','u','n','O','n','c','e',0};
6759 static const WCHAR InstallRunOnce[] = {
6760 'S','o','f','t','w','a','r','e','\\',
6761 'M','i','c','r','o','s','o','f','t','\\',
6762 'W','i','n','d','o','w','s','\\',
6763 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
6764 'I','n','s','t','a','l','l','e','r','\\',
6765 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
6767 static const WCHAR msiexec_fmt[] = {
6769 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
6770 '\"','%','s','\"',0};
6771 static const WCHAR install_fmt[] = {
6772 '/','I',' ','\"','%','s','\"',' ',
6773 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
6774 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
6775 WCHAR buffer[256], sysdir[MAX_PATH];
6778 WCHAR squished_pc[100];
6781 static const WCHAR szLUS[] = {
6782 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0};
6783 static const WCHAR szSourceList[] = {
6784 'S','o','u','r','c','e','L','i','s','t',0};
6785 static const WCHAR szPackageName[] = {
6786 'P','a','c','k','a','g','e','N','a','m','e',0};
6789 return ERROR_INVALID_HANDLE;
6791 productcode = load_dynamic_property(package,szProductCode,&rc);
6795 squash_guid(productcode,squished_pc);
6797 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
6798 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
6799 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
6802 size = strlenW(buffer)*sizeof(WCHAR);
6803 RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
6806 TRACE("Reboot command %s\n",debugstr_w(buffer));
6808 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
6809 sprintfW(buffer,install_fmt,productcode,squished_pc);
6811 size = strlenW(buffer)*sizeof(WCHAR);
6812 RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
6815 rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
6816 if (rc == ERROR_SUCCESS)
6820 RegCreateKeyW(hukey, szSourceList, &hukey2);
6821 buf = load_dynamic_property(package,cszSourceDir,NULL);
6822 size = strlenW(buf)*sizeof(WCHAR);
6823 RegSetValueExW(hukey2,szLUS,0,REG_SZ,(LPSTR)buf,size);
6824 HeapFree(GetProcessHeap(),0,buf);
6826 buf = strrchrW(package->PackagePath,'\\');
6830 size = strlenW(buf)*sizeof(WCHAR);
6831 RegSetValueExW(hukey2,szPackageName,0,REG_SZ,(LPSTR)buf,size);
6834 RegCloseKey(hukey2);
6836 HeapFree(GetProcessHeap(),0,productcode);
6838 return ERROR_INSTALL_SUSPEND;
6841 UINT ACTION_ResolveSource(MSIPACKAGE* package)
6844 * we are currently doing what should be done here in the top level Install
6845 * however for Adminastrative and uninstalls this step will be needed
6847 return ERROR_SUCCESS;
6850 static LPWSTR create_component_advertise_string(MSIPACKAGE* package,
6851 MSICOMPONENT* component, LPCWSTR feature)
6853 LPWSTR productid=NULL;
6855 WCHAR productid_85[21];
6856 WCHAR component_85[21];
6858 * I have a fair bit of confusion as to when a < is used and when a > is
6859 * used. I do not think i have it right...
6861 * Ok it appears that the > is used if there is a guid for the compoenent
6862 * and the < is used if not.
6864 static WCHAR fmt1[] = {'%','s','%','s','<',0,0};
6865 static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0};
6866 LPWSTR output = NULL;
6869 memset(productid_85,0,sizeof(productid_85));
6870 memset(component_85,0,sizeof(component_85));
6872 productid = load_dynamic_property(package,szProductCode,NULL);
6873 CLSIDFromString(productid, &clsid);
6875 encode_base85_guid(&clsid,productid_85);
6877 CLSIDFromString(component->ComponentId, &clsid);
6878 encode_base85_guid(&clsid,component_85);
6880 TRACE("Doing something with this... %s %s %s\n",
6881 debugstr_w(productid_85), debugstr_w(feature),
6882 debugstr_w(component_85));
6884 sz = lstrlenW(productid_85) + lstrlenW(feature);
6886 sz += lstrlenW(component_85);
6889 sz *= sizeof(WCHAR);
6891 output = HeapAlloc(GetProcessHeap(),0,sz);
6892 memset(output,0,sz);
6895 sprintfW(output,fmt2,productid_85,feature,component_85);
6897 sprintfW(output,fmt1,productid_85,feature);
6899 HeapFree(GetProcessHeap(),0,productid);
6904 static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid,
6905 MSICOMPONENT* component, MSIEXTENSION* extension,
6906 MSIVERB* verb, INT* Sequence )
6910 static const WCHAR szShell[] = {'s','h','e','l','l',0};
6911 static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0};
6912 static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0};
6913 static const WCHAR fmt2[] = {'\"','%','s','\"',0};
6918 keyname = build_directory_name(4, progid, szShell, verb->Verb, szCommand);
6920 TRACE("Making Key %s\n",debugstr_w(keyname));
6921 RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
6922 size = strlenW(component->FullKeypath);
6924 size += strlenW(verb->Argument);
6927 command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
6929 sprintfW(command, fmt, component->FullKeypath, verb->Argument);
6931 sprintfW(command, fmt2, component->FullKeypath);
6933 RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)command, (strlenW(command)+1)*
6935 HeapFree(GetProcessHeap(),0,command);
6937 advertise = create_component_advertise_string(package, component,
6938 package->features[extension->FeatureIndex].Feature);
6940 size = strlenW(advertise);
6943 size += strlenW(verb->Argument);
6946 command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
6947 memset(command,0,size*sizeof(WCHAR));
6949 strcpyW(command,advertise);
6952 static const WCHAR szSpace[] = {' ',0};
6953 strcatW(command,szSpace);
6954 strcatW(command,verb->Argument);
6957 RegSetValueExW(key, szCommand, 0, REG_MULTI_SZ, (LPBYTE)command,
6958 (strlenW(command)+2)*sizeof(WCHAR));
6961 HeapFree(GetProcessHeap(),0,keyname);
6962 HeapFree(GetProcessHeap(),0,advertise);
6963 HeapFree(GetProcessHeap(),0,command);
6967 keyname = build_directory_name(3, progid, szShell, verb->Verb);
6968 RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
6969 RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Command,
6970 (strlenW(verb->Command)+1) *sizeof(WCHAR));
6972 HeapFree(GetProcessHeap(),0,keyname);
6975 if (verb->Sequence != MSI_NULL_INTEGER)
6977 if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence)
6979 *Sequence = verb->Sequence;
6980 keyname = build_directory_name(2, progid, szShell);
6981 RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
6982 RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Verb,
6983 (strlenW(verb->Verb)+1) *sizeof(WCHAR));
6985 HeapFree(GetProcessHeap(),0,keyname);
6988 return ERROR_SUCCESS;
6991 static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
6993 static const WCHAR szContentType[] =
6994 {'C','o','n','t','e','n','t',' ','T','y','p','e',0 };
7000 return ERROR_INVALID_HANDLE;
7002 load_classes_and_such(package);
7004 for (i = 0; i < package->loaded_extensions; i++)
7006 WCHAR extension[257];
7009 index = package->extensions[i].ComponentIndex;
7010 f_index = package->extensions[i].FeatureIndex;
7016 * yes. MSDN says that these are based on _Feature_ not on
7017 * Component. So verify the feature is to be installed
7019 if ((!ACTION_VerifyFeatureForAction(package, f_index,
7020 INSTALLSTATE_LOCAL)) &&
7021 (!ACTION_VerifyFeatureForAction(package, f_index,
7022 INSTALLSTATE_ADVERTISED)))
7024 TRACE("Skipping extension %s reg due to disabled feature %s\n",
7025 debugstr_w(package->extensions[i].Extension),
7026 debugstr_w(package->features[f_index].Feature));
7031 TRACE("Registering extension %s index %i\n",
7032 debugstr_w(package->extensions[i].Extension), i);
7034 package->extensions[i].Installed = TRUE;
7036 if (package->extensions[i].ProgIDIndex >= 0)
7037 mark_progid_for_install(package, package->extensions[i].ProgIDIndex);
7039 if (package->extensions[i].MIMEIndex >= 0)
7040 mark_mime_for_install(package, package->extensions[i].MIMEIndex);
7044 strcatW(extension,package->extensions[i].Extension);
7046 RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey);
7048 if (package->extensions[i].MIMEIndex >= 0)
7050 RegSetValueExW(hkey,szContentType,0,REG_SZ,
7051 (LPVOID)package->mimes[package->extensions[i].
7052 MIMEIndex].ContentType,
7053 (strlenW(package->mimes[package->extensions[i].
7054 MIMEIndex].ContentType)+1)*sizeof(WCHAR));
7057 if (package->extensions[i].ProgIDIndex >= 0 ||
7058 package->extensions[i].ProgIDText)
7060 static const WCHAR szSN[] =
7061 {'\\','S','h','e','l','l','N','e','w',0};
7066 INT Sequence = MSI_NULL_INTEGER;
7068 if (package->extensions[i].ProgIDIndex >= 0)
7069 progid = package->progids[package->extensions[i].
7070 ProgIDIndex].ProgID;
7072 progid = package->extensions[i].ProgIDText;
7074 RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid,
7075 (strlenW(progid)+1)*sizeof(WCHAR));
7077 newkey = HeapAlloc(GetProcessHeap(),0,
7078 (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR));
7080 strcpyW(newkey,progid);
7081 strcatW(newkey,szSN);
7082 RegCreateKeyW(hkey,newkey,&hkey2);
7085 HeapFree(GetProcessHeap(),0,newkey);
7087 /* do all the verbs */
7088 for (v = 0; v < package->extensions[i].VerbCount; v++)
7089 register_verb(package, progid,
7090 &package->components[index],
7091 &package->extensions[i],
7092 &package->verbs[package->extensions[i].Verbs[v]],
7098 uirow = MSI_CreateRecord(1);
7099 MSI_RecordSetStringW(uirow,1,package->extensions[i].Extension);
7100 ui_actiondata(package,szRegisterExtensionInfo,uirow);
7101 msiobj_release(&uirow->hdr);
7104 return ERROR_SUCCESS;
7107 static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
7109 static const WCHAR szExten[] =
7110 {'E','x','t','e','n','s','i','o','n',0 };
7116 return ERROR_INVALID_HANDLE;
7118 load_classes_and_such(package);
7120 for (i = 0; i < package->loaded_mimes; i++)
7122 WCHAR extension[257];
7125 static const WCHAR fmt[] =
7126 {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
7127 'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0};
7131 * check if the MIME is to be installed. Either as requesed by an
7132 * extension or Class
7134 package->mimes[i].InstallMe = ((package->mimes[i].InstallMe) ||
7135 (package->mimes[i].ClassIndex >= 0 &&
7136 package->classes[package->mimes[i].ClassIndex].Installed) ||
7137 (package->mimes[i].ExtensionIndex >=0 &&
7138 package->extensions[package->mimes[i].ExtensionIndex].Installed));
7140 if (!package->mimes[i].InstallMe)
7142 TRACE("MIME %s not scheduled to be installed\n",
7143 debugstr_w(package->mimes[i].ContentType));
7147 mime = package->mimes[i].ContentType;
7148 exten = package->extensions[package->mimes[i].ExtensionIndex].Extension;
7151 strcatW(extension,exten);
7153 key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) *
7155 sprintfW(key,fmt,mime);
7156 RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey);
7157 RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension,
7158 (strlenW(extension)+1)*sizeof(WCHAR));
7160 HeapFree(GetProcessHeap(),0,key);
7162 if (package->mimes[i].CLSID[0])
7164 FIXME("Handle non null for field 3\n");
7169 uirow = MSI_CreateRecord(2);
7170 MSI_RecordSetStringW(uirow,1,package->mimes[i].ContentType);
7171 MSI_RecordSetStringW(uirow,2,exten);
7172 ui_actiondata(package,szRegisterMIMEInfo,uirow);
7173 msiobj_release(&uirow->hdr);
7176 return ERROR_SUCCESS;
7179 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
7181 static const WCHAR szProductID[]=
7182 {'P','r','o','d','u','c','t','I','D',0};
7190 static const WCHAR szPropKeys[][80] =
7192 {'P','r','o','d','u','c','t','I','D',0},
7193 {'U','S','E','R','N','A','M','E',0},
7194 {'C','O','M','P','A','N','Y','N','A','M','E',0},
7198 static const WCHAR szRegKeys[][80] =
7200 {'P','r','o','d','u','c','t','I','D',0},
7201 {'R','e','g','O','w','n','e','r',0},
7202 {'R','e','g','C','o','m','p','a','n','y',0},
7207 return ERROR_INVALID_HANDLE;
7209 productid = load_dynamic_property(package,szProductID,&rc);
7211 return ERROR_SUCCESS;
7213 productcode = load_dynamic_property(package,szProductCode,&rc);
7217 rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
7218 if (rc != ERROR_SUCCESS)
7222 while (szPropKeys[i][0]!=0)
7224 buffer = load_dynamic_property(package,szPropKeys[i],&rc);
7225 if (rc == ERROR_SUCCESS)
7227 size = strlenW(buffer)*sizeof(WCHAR);
7228 RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);
7231 RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,NULL,0);
7236 HeapFree(GetProcessHeap(),0,productcode);
7237 HeapFree(GetProcessHeap(),0,productid);
7240 return ERROR_SUCCESS;
7244 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
7247 rc = ACTION_ProcessExecSequence(package,FALSE);
7253 * Code based off of code located here
7254 * http://www.codeproject.com/gdi/fontnamefromfile.asp
7256 * Using string index 4 (full font name) instead of 1 (family name)
7258 static LPWSTR load_ttfname_from(LPCWSTR filename)
7264 typedef struct _tagTT_OFFSET_TABLE{
7265 USHORT uMajorVersion;
7266 USHORT uMinorVersion;
7267 USHORT uNumOfTables;
7268 USHORT uSearchRange;
7269 USHORT uEntrySelector;
7273 typedef struct _tagTT_TABLE_DIRECTORY{
7274 char szTag[4]; /* table name */
7275 ULONG uCheckSum; /* Check sum */
7276 ULONG uOffset; /* Offset from beginning of file */
7277 ULONG uLength; /* length of the table in bytes */
7278 }TT_TABLE_DIRECTORY;
7280 typedef struct _tagTT_NAME_TABLE_HEADER{
7281 USHORT uFSelector; /* format selector. Always 0 */
7282 USHORT uNRCount; /* Name Records count */
7283 USHORT uStorageOffset; /* Offset for strings storage,
7284 * from start of the table */
7285 }TT_NAME_TABLE_HEADER;
7287 typedef struct _tagTT_NAME_RECORD{
7292 USHORT uStringLength;
7293 USHORT uStringOffset; /* from start of storage area */
7296 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
7297 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
7299 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
7300 FILE_ATTRIBUTE_NORMAL, 0 );
7301 if (handle != INVALID_HANDLE_VALUE)
7303 TT_TABLE_DIRECTORY tblDir;
7304 BOOL bFound = FALSE;
7305 TT_OFFSET_TABLE ttOffsetTable;
7307 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),NULL,NULL);
7308 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
7309 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
7310 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
7312 if (ttOffsetTable.uMajorVersion != 1 ||
7313 ttOffsetTable.uMinorVersion != 0)
7316 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
7318 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),NULL,NULL);
7319 if (strncmp(tblDir.szTag,"name",4)==0)
7322 tblDir.uLength = SWAPLONG(tblDir.uLength);
7323 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
7330 TT_NAME_TABLE_HEADER ttNTHeader;
7331 TT_NAME_RECORD ttRecord;
7333 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
7334 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
7337 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
7338 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
7340 for(i=0; i<ttNTHeader.uNRCount; i++)
7342 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),NULL,NULL);
7343 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
7344 /* 4 is the Full Font Name */
7345 if(ttRecord.uNameID == 4)
7349 static const LPSTR tt = " (TrueType)";
7351 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
7352 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
7353 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
7354 SetFilePointer(handle, tblDir.uOffset +
7355 ttRecord.uStringOffset +
7356 ttNTHeader.uStorageOffset,
7358 buf = HeapAlloc(GetProcessHeap(), 0,
7359 ttRecord.uStringLength + 1 + strlen(tt));
7360 memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
7361 ReadFile(handle, buf, ttRecord.uStringLength, NULL, NULL);
7362 if (strlen(buf) > 0)
7365 ret = strdupAtoW(buf);
7366 HeapFree(GetProcessHeap(),0,buf);
7370 HeapFree(GetProcessHeap(),0,buf);
7371 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
7375 CloseHandle(handle);
7378 ERR("Unable to open font file %s\n", debugstr_w(filename));
7380 TRACE("Returning fontname %s\n",debugstr_w(ret));
7384 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
7388 MSIRECORD * row = 0;
7389 static const WCHAR ExecSeqQuery[] =
7390 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7391 '`','F','o','n','t','`',0};
7392 static const WCHAR regfont1[] =
7393 {'S','o','f','t','w','a','r','e','\\',
7394 'M','i','c','r','o','s','o','f','t','\\',
7395 'W','i','n','d','o','w','s',' ','N','T','\\',
7396 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
7397 'F','o','n','t','s',0};
7398 static const WCHAR regfont2[] =
7399 {'S','o','f','t','w','a','r','e','\\',
7400 'M','i','c','r','o','s','o','f','t','\\',
7401 'W','i','n','d','o','w','s','\\',
7402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
7403 'F','o','n','t','s',0};
7407 TRACE("%p\n", package);
7409 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
7410 if (rc != ERROR_SUCCESS)
7412 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
7413 return ERROR_SUCCESS;
7416 rc = MSI_ViewExecute(view, 0);
7417 if (rc != ERROR_SUCCESS)
7419 MSI_ViewClose(view);
7420 msiobj_release(&view->hdr);
7421 TRACE("MSI_ViewExecute returned %d\n", rc);
7422 return ERROR_SUCCESS;
7425 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
7426 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
7435 rc = MSI_ViewFetch(view,&row);
7436 if (rc != ERROR_SUCCESS)
7442 file = load_dynamic_stringW(row,1);
7443 index = get_loaded_file(package,file);
7446 ERR("Unable to load file\n");
7447 HeapFree(GetProcessHeap(),0,file);
7451 /* check to make sure that component is installed */
7452 if (!ACTION_VerifyComponentForAction(package,
7453 package->files[index].ComponentIndex, INSTALLSTATE_LOCAL))
7455 TRACE("Skipping: Component not scheduled for install\n");
7456 HeapFree(GetProcessHeap(),0,file);
7458 msiobj_release(&row->hdr);
7463 if (MSI_RecordIsNull(row,2))
7464 name = load_ttfname_from(package->files[index].TargetPath);
7466 name = load_dynamic_stringW(row,2);
7470 size = strlenW(package->files[index].FileName) * sizeof(WCHAR);
7471 RegSetValueExW(hkey1,name,0,REG_SZ,
7472 (LPBYTE)package->files[index].FileName,size);
7473 RegSetValueExW(hkey2,name,0,REG_SZ,
7474 (LPBYTE)package->files[index].FileName,size);
7477 HeapFree(GetProcessHeap(),0,file);
7478 HeapFree(GetProcessHeap(),0,name);
7479 msiobj_release(&row->hdr);
7481 MSI_ViewClose(view);
7482 msiobj_release(&view->hdr);
7487 TRACE("returning %d\n", rc);
7491 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
7493 MSIPACKAGE *package = (MSIPACKAGE*)param;
7494 LPWSTR compgroupid=NULL;
7495 LPWSTR feature=NULL;
7497 LPWSTR qualifier = NULL;
7498 LPWSTR component = NULL;
7499 LPWSTR advertise = NULL;
7500 LPWSTR output = NULL;
7502 UINT rc = ERROR_SUCCESS;
7506 component = load_dynamic_stringW(rec,3);
7507 index = get_loaded_component(package,component);
7509 if (!ACTION_VerifyComponentForAction(package, index,
7510 INSTALLSTATE_LOCAL) &&
7511 !ACTION_VerifyComponentForAction(package, index,
7512 INSTALLSTATE_SOURCE) &&
7513 !ACTION_VerifyComponentForAction(package, index,
7514 INSTALLSTATE_ADVERTISED))
7516 TRACE("Skipping: Component %s not scheduled for install\n",
7517 debugstr_w(component));
7519 HeapFree(GetProcessHeap(),0,component);
7520 return ERROR_SUCCESS;
7523 compgroupid = load_dynamic_stringW(rec,1);
7525 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
7526 if (rc != ERROR_SUCCESS)
7529 text = load_dynamic_stringW(rec,4);
7530 qualifier = load_dynamic_stringW(rec,2);
7531 feature = load_dynamic_stringW(rec,5);
7533 advertise = create_component_advertise_string(package,
7534 &package->components[index], feature);
7536 sz = strlenW(advertise);
7539 sz += lstrlenW(text);
7542 sz *= sizeof(WCHAR);
7544 output = HeapAlloc(GetProcessHeap(),0,sz);
7545 memset(output,0,sz);
7546 strcpyW(output,advertise);
7549 strcatW(output,text);
7551 sz = (lstrlenW(output)+2) * sizeof(WCHAR);
7552 RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz);
7556 HeapFree(GetProcessHeap(),0,output);
7557 HeapFree(GetProcessHeap(),0,compgroupid);
7558 HeapFree(GetProcessHeap(),0,component);
7559 HeapFree(GetProcessHeap(),0,feature);
7560 HeapFree(GetProcessHeap(),0,text);
7561 HeapFree(GetProcessHeap(),0,qualifier);
7567 * At present I am ignorning the advertised components part of this and only
7568 * focusing on the qualified component sets
7570 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
7574 static const WCHAR ExecSeqQuery[] =
7575 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7576 '`','P','u','b','l','i','s','h',
7577 'C','o','m','p','o','n','e','n','t','`',0};
7579 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
7580 if (rc != ERROR_SUCCESS)
7581 return ERROR_SUCCESS;
7583 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
7584 msiobj_release(&view->hdr);
7589 /* Msi functions that seem appropriate here */
7591 /***********************************************************************
7592 * MsiDoActionA (MSI.@)
7594 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
7599 TRACE(" exteral attempt at action %s\n",szAction);
7602 return ERROR_FUNCTION_FAILED;
7604 return ERROR_FUNCTION_FAILED;
7606 szwAction = strdupAtoW(szAction);
7609 return ERROR_FUNCTION_FAILED;
7612 rc = MsiDoActionW(hInstall, szwAction);
7613 HeapFree(GetProcessHeap(),0,szwAction);
7617 /***********************************************************************
7618 * MsiDoActionW (MSI.@)
7620 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
7622 MSIPACKAGE *package;
7623 UINT ret = ERROR_INVALID_HANDLE;
7625 TRACE(" external attempt at action %s \n",debugstr_w(szAction));
7627 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7630 ret = ACTION_PerformUIAction(package,szAction);
7631 msiobj_release( &package->hdr );
7636 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
7637 LPSTR szPathBuf, DWORD* pcchPathBuf)
7643 TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
7646 return ERROR_FUNCTION_FAILED;
7648 return ERROR_FUNCTION_FAILED;
7650 szwFolder = strdupAtoW(szFolder);
7653 return ERROR_FUNCTION_FAILED;
7655 szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
7657 rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
7659 WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
7660 *pcchPathBuf, NULL, NULL );
7662 HeapFree(GetProcessHeap(),0,szwFolder);
7663 HeapFree(GetProcessHeap(),0,szwPathBuf);
7668 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
7669 szPathBuf, DWORD* pcchPathBuf)
7672 UINT rc = ERROR_FUNCTION_FAILED;
7673 MSIPACKAGE *package;
7675 TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
7677 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7679 return ERROR_INVALID_HANDLE;
7680 path = resolve_folder(package, szFolder, FALSE, FALSE, NULL);
7681 msiobj_release( &package->hdr );
7683 if (path && (strlenW(path) > *pcchPathBuf))
7685 *pcchPathBuf = strlenW(path)+1;
7686 rc = ERROR_MORE_DATA;
7690 *pcchPathBuf = strlenW(path)+1;
7691 strcpyW(szPathBuf,path);
7692 TRACE("Returning Path %s\n",debugstr_w(path));
7695 HeapFree(GetProcessHeap(),0,path);
7701 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder,
7702 LPSTR szPathBuf, DWORD* pcchPathBuf)
7708 TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
7711 return ERROR_FUNCTION_FAILED;
7713 return ERROR_FUNCTION_FAILED;
7715 szwFolder = strdupAtoW(szFolder);
7717 return ERROR_FUNCTION_FAILED;
7719 szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
7721 rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
7723 WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
7724 *pcchPathBuf, NULL, NULL );
7726 HeapFree(GetProcessHeap(),0,szwFolder);
7727 HeapFree(GetProcessHeap(),0,szwPathBuf);
7732 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
7733 szPathBuf, DWORD* pcchPathBuf)
7736 UINT rc = ERROR_FUNCTION_FAILED;
7737 MSIPACKAGE *package;
7739 TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
7741 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7743 return ERROR_INVALID_HANDLE;
7744 path = resolve_folder(package, szFolder, TRUE, FALSE, NULL);
7745 msiobj_release( &package->hdr );
7747 if (path && strlenW(path) > *pcchPathBuf)
7749 *pcchPathBuf = strlenW(path)+1;
7750 rc = ERROR_MORE_DATA;
7754 *pcchPathBuf = strlenW(path)+1;
7755 strcpyW(szPathBuf,path);
7756 TRACE("Returning Path %s\n",debugstr_w(path));
7759 HeapFree(GetProcessHeap(),0,path);
7765 /***********************************************************************
7766 * MsiSetTargetPathA (MSI.@)
7768 UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder,
7769 LPCSTR szFolderPath)
7772 LPWSTR szwFolderPath;
7776 return ERROR_FUNCTION_FAILED;
7778 return ERROR_FUNCTION_FAILED;
7780 szwFolder = strdupAtoW(szFolder);
7782 return ERROR_FUNCTION_FAILED;
7784 szwFolderPath = strdupAtoW(szFolderPath);
7787 HeapFree(GetProcessHeap(),0,szwFolder);
7788 return ERROR_FUNCTION_FAILED;
7791 rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
7793 HeapFree(GetProcessHeap(),0,szwFolder);
7794 HeapFree(GetProcessHeap(),0,szwFolderPath);
7799 UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
7800 LPCWSTR szFolderPath)
7804 LPWSTR path2 = NULL;
7807 TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
7810 return ERROR_INVALID_HANDLE;
7812 if (szFolderPath[0]==0)
7813 return ERROR_FUNCTION_FAILED;
7815 if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)
7816 return ERROR_FUNCTION_FAILED;
7818 path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);
7821 return ERROR_INVALID_PARAMETER;
7823 HeapFree(GetProcessHeap(),0,folder->Property);
7824 folder->Property = build_directory_name(2, szFolderPath, NULL);
7826 if (lstrcmpiW(path, folder->Property) == 0)
7829 * Resolved Target has not really changed, so just
7830 * set this folder and do not recalculate everything.
7832 HeapFree(GetProcessHeap(),0,folder->ResolvedTarget);
7833 folder->ResolvedTarget = NULL;
7834 path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL);
7835 HeapFree(GetProcessHeap(),0,path2);
7839 for (i = 0; i < package->loaded_folders; i++)
7841 HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
7842 package->folders[i].ResolvedTarget=NULL;
7845 for (i = 0; i < package->loaded_folders; i++)
7847 path2=resolve_folder(package, package->folders[i].Directory, FALSE,
7849 HeapFree(GetProcessHeap(),0,path2);
7852 HeapFree(GetProcessHeap(),0,path);
7854 return ERROR_SUCCESS;
7857 /***********************************************************************
7858 * MsiSetTargetPathW (MSI.@)
7860 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
7861 LPCWSTR szFolderPath)
7863 MSIPACKAGE *package;
7866 TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
7868 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7869 ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
7870 msiobj_release( &package->hdr );
7874 /***********************************************************************
7875 * MsiGetMode (MSI.@)
7877 * Returns an internal installer state (if it is running in a mode iRunMode)
7880 * hInstall [I] Handle to the installation
7881 * hRunMode [I] Checking run mode
7882 * MSIRUNMODE_ADMIN Administrative mode
7883 * MSIRUNMODE_ADVERTISE Advertisement mode
7884 * MSIRUNMODE_MAINTENANCE Maintenance mode
7885 * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled
7886 * MSIRUNMODE_LOGENABLED Log file is writing
7887 * MSIRUNMODE_OPERATIONS Operations in progress??
7888 * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed
7889 * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation
7890 * MSIRUNMODE_CABINET Files from cabinet are installed
7891 * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is suppressed
7892 * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is suppressed
7893 * MSIRUNMODE_RESERVED11 Reserved
7894 * MSIRUNMODE_WINDOWS9X Running under Windows95/98
7895 * MSIRUNMODE_ZAWENABLED Demand installation is supported
7896 * MSIRUNMODE_RESERVED14 Reserved
7897 * MSIRUNMODE_RESERVED15 Reserved
7898 * MSIRUNMODE_SCHEDULED called from install script
7899 * MSIRUNMODE_ROLLBACK called from rollback script
7900 * MSIRUNMODE_COMMIT called from commit script
7903 * In the state: TRUE
7904 * Not in the state: FALSE
7908 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
7910 FIXME("STUB (iRunMode=%i)\n",iRunMode);
7914 /***********************************************************************
7915 * MsiSetFeatureStateA (MSI.@)
7917 * According to the docs, when this is called it immediately recalculates
7918 * all the component states as well
7920 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
7921 INSTALLSTATE iState)
7923 LPWSTR szwFeature = NULL;
7926 szwFeature = strdupAtoW(szFeature);
7929 return ERROR_FUNCTION_FAILED;
7931 rc = MsiSetFeatureStateW(hInstall,szwFeature, iState);
7933 HeapFree(GetProcessHeap(),0,szwFeature);
7940 UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
7941 INSTALLSTATE iState)
7944 UINT rc = ERROR_SUCCESS;
7946 TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
7948 index = get_loaded_feature(package,szFeature);
7950 return ERROR_UNKNOWN_FEATURE;
7952 package->features[index].ActionRequest= iState;
7953 package->features[index].Action= iState;
7955 ACTION_UpdateComponentStates(package,szFeature);
7957 /* update all the features that are children of this feature */
7958 for (i = 0; i < package->loaded_features; i++)
7960 if (strcmpW(szFeature, package->features[i].Feature_Parent) == 0)
7961 MSI_SetFeatureStateW(package, package->features[i].Feature, iState);
7967 /***********************************************************************
7968 * MsiSetFeatureStateW (MSI.@)
7970 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
7971 INSTALLSTATE iState)
7973 MSIPACKAGE* package;
7974 UINT rc = ERROR_SUCCESS;
7976 TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
7978 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7980 return ERROR_INVALID_HANDLE;
7982 rc = MSI_SetFeatureStateW(package,szFeature,iState);
7984 msiobj_release( &package->hdr );
7988 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
7989 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7991 LPWSTR szwFeature = NULL;
7994 szwFeature = strdupAtoW(szFeature);
7996 rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
7998 HeapFree( GetProcessHeap(), 0 , szwFeature);
8003 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
8004 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
8008 index = get_loaded_feature(package,szFeature);
8010 return ERROR_UNKNOWN_FEATURE;
8013 *piInstalled = package->features[index].Installed;
8016 *piAction = package->features[index].Action;
8018 TRACE("returning %i %i\n",*piInstalled,*piAction);
8020 return ERROR_SUCCESS;
8023 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
8024 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
8026 MSIPACKAGE* package;
8029 TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
8032 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
8034 return ERROR_INVALID_HANDLE;
8035 ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
8036 msiobj_release( &package->hdr );
8040 /***********************************************************************
8041 * MsiGetComponentStateA (MSI.@)
8043 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
8044 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
8046 LPWSTR szwComponent= NULL;
8049 szwComponent= strdupAtoW(szComponent);
8051 rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
8053 HeapFree( GetProcessHeap(), 0 , szwComponent);
8058 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
8059 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
8063 TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
8066 index = get_loaded_component(package,szComponent);
8068 return ERROR_UNKNOWN_COMPONENT;
8071 *piInstalled = package->components[index].Installed;
8074 *piAction = package->components[index].Action;
8076 TRACE("states (%i, %i)\n",
8077 (piInstalled)?*piInstalled:-1,(piAction)?*piAction:-1);
8079 return ERROR_SUCCESS;
8082 /***********************************************************************
8083 * MsiGetComponentStateW (MSI.@)
8085 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
8086 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
8088 MSIPACKAGE* package;
8091 TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
8092 piInstalled, piAction);
8094 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
8096 return ERROR_INVALID_HANDLE;
8097 ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
8098 msiobj_release( &package->hdr );