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 for (i = 0; i < package->DeferredActionCount; i++)
620 HeapFree(GetProcessHeap(),0,package->DeferredAction[i]);
621 HeapFree(GetProcessHeap(),0,package->DeferredAction);
623 for (i = 0; i < package->CommitActionCount; i++)
624 HeapFree(GetProcessHeap(),0,package->CommitAction[i]);
625 HeapFree(GetProcessHeap(),0,package->CommitAction);
627 HeapFree(GetProcessHeap(),0,package->PackagePath);
630 static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )
634 row = MSI_CreateRecord(4);
635 MSI_RecordSetInteger(row,1,a);
636 MSI_RecordSetInteger(row,2,b);
637 MSI_RecordSetInteger(row,3,c);
638 MSI_RecordSetInteger(row,4,d);
639 MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);
640 msiobj_release(&row->hdr);
642 msi_dialog_check_messages(NULL);
645 static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
647 static const WCHAR Query_t[] =
648 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
649 'A','c','t','i','o', 'n','T','e','x','t',' ','W','H','E','R','E',' ',
650 'A','c','t','i','o','n',' ','=', ' ','\'','%','s','\'',0};
657 if (!package->LastAction || strcmpW(package->LastAction,action))
659 rc = MSI_OpenQuery(package->db, &view, Query_t, action);
660 if (rc != ERROR_SUCCESS)
663 rc = MSI_ViewExecute(view, 0);
664 if (rc != ERROR_SUCCESS)
667 msiobj_release(&view->hdr);
670 rc = MSI_ViewFetch(view,&row);
671 if (rc != ERROR_SUCCESS)
674 msiobj_release(&view->hdr);
678 if (MSI_RecordIsNull(row,3))
680 msiobj_release(&row->hdr);
682 msiobj_release(&view->hdr);
686 /* update the cached actionformat */
687 HeapFree(GetProcessHeap(),0,package->ActionFormat);
688 package->ActionFormat = load_dynamic_stringW(row,3);
690 HeapFree(GetProcessHeap(),0,package->LastAction);
691 package->LastAction = strdupW(action);
693 msiobj_release(&row->hdr);
695 msiobj_release(&view->hdr);
698 MSI_RecordSetStringW(record,0,package->ActionFormat);
700 MSI_FormatRecordW(package,record,message,&size);
702 row = MSI_CreateRecord(1);
703 MSI_RecordSetStringW(row,1,message);
705 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
706 msiobj_release(&row->hdr);
710 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
712 static const WCHAR template_s[]=
713 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
715 static const WCHAR format[] =
716 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
717 static const WCHAR Query_t[] =
718 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
719 'A','c','t','i','o', 'n','T','e','x','t',' ','W','H','E','R','E', ' ',
720 'A','c','t','i','o','n',' ','=', ' ','\'','%','s','\'',0};
726 WCHAR *ActionText=NULL;
728 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
730 rc = MSI_OpenQuery(package->db, &view, Query_t, action);
731 if (rc != ERROR_SUCCESS)
733 rc = MSI_ViewExecute(view, 0);
734 if (rc != ERROR_SUCCESS)
737 msiobj_release(&view->hdr);
740 rc = MSI_ViewFetch(view,&row);
741 if (rc != ERROR_SUCCESS)
744 msiobj_release(&view->hdr);
748 ActionText = load_dynamic_stringW(row,2);
749 msiobj_release(&row->hdr);
751 msiobj_release(&view->hdr);
753 sprintfW(message,template_s,timet,action,ActionText);
755 row = MSI_CreateRecord(1);
756 MSI_RecordSetStringW(row,1,message);
758 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
759 msiobj_release(&row->hdr);
760 HeapFree(GetProcessHeap(),0,ActionText);
763 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
767 static const WCHAR template_s[]=
768 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
770 static const WCHAR template_e[]=
771 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
772 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
774 static const WCHAR format[] =
775 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
779 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
781 sprintfW(message,template_s,timet,action);
783 sprintfW(message,template_e,timet,action,rc);
785 row = MSI_CreateRecord(1);
786 MSI_RecordSetStringW(row,1,message);
788 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
789 msiobj_release(&row->hdr);
793 * build_directory_name()
795 * This function is to save messing round with directory names
796 * It handles adding backslashes between path segments,
797 * and can add \ at the end of the directory name if told to.
799 * It takes a variable number of arguments.
800 * It always allocates a new string for the result, so make sure
801 * to free the return value when finished with it.
803 * The first arg is the number of path segments that follow.
804 * The arguments following count are a list of path segments.
805 * A path segment may be NULL.
807 * Path segments will be added with a \ separating them.
808 * A \ will not be added after the last segment, however if the
809 * last segment is NULL, then the last character will be a \
812 static LPWSTR build_directory_name(DWORD count, ...)
819 for(i=0; i<count; i++)
821 LPCWSTR str = va_arg(va,LPCWSTR);
823 sz += strlenW(str) + 1;
827 dir = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
831 for(i=0; i<count; i++)
833 LPCWSTR str = va_arg(va,LPCWSTR);
837 if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\\')
843 static BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, INT index,
846 if (package->components[index].Installed == check)
849 if (package->components[index].ActionRequest == check)
855 static BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE* package, INT index,
858 if (package->features[index].Installed == check)
861 if (package->features[index].ActionRequest == check)
868 /****************************************************
869 * TOP level entry points
870 *****************************************************/
872 UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
873 LPCWSTR szCommandLine)
879 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
880 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
881 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
883 MSI_SetPropertyW(package, szAction, szInstall);
884 package->ExecuteSequenceRun = FALSE;
888 LPWSTR p, check, path;
890 package->PackagePath = strdupW(szPackagePath);
891 path = strdupW(szPackagePath);
892 p = strrchrW(path,'\\');
900 HeapFree(GetProcessHeap(),0,path);
901 path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR));
902 GetCurrentDirectoryW(MAX_PATH,path);
906 check = load_dynamic_property(package, cszSourceDir,NULL);
908 MSI_SetPropertyW(package, cszSourceDir, path);
910 HeapFree(GetProcessHeap(), 0, check);
912 HeapFree(GetProcessHeap(), 0, path);
918 ptr = (LPWSTR)szCommandLine;
925 TRACE("Looking at %s\n",debugstr_w(ptr));
927 ptr2 = strchrW(ptr,'=');
933 while (*ptr == ' ') ptr++;
935 prop = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
936 memcpy(prop,ptr,len*sizeof(WCHAR));
942 while (*ptr && (quote || (!quote && *ptr!=' ')))
955 val = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
956 memcpy(val,ptr2,len*sizeof(WCHAR));
959 if (strlenW(prop) > 0)
961 TRACE("Found commandline property (%s) = (%s)\n",
962 debugstr_w(prop), debugstr_w(val));
963 MSI_SetPropertyW(package,prop,val);
965 HeapFree(GetProcessHeap(),0,val);
966 HeapFree(GetProcessHeap(),0,prop);
973 if (MSI_GetPropertyW(package,szUILevel,buffer,&sz) == ERROR_SUCCESS)
975 if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED)
977 rc = ACTION_ProcessUISequence(package);
979 if (rc == ERROR_SUCCESS)
980 rc = ACTION_ProcessExecSequence(package,TRUE);
983 rc = ACTION_ProcessExecSequence(package,FALSE);
986 rc = ACTION_ProcessExecSequence(package,FALSE);
990 /* install was halted but should be considered a success */
994 /* process the ending type action */
995 if (rc == ERROR_SUCCESS)
996 ACTION_PerformActionSequence(package,-1,ui);
997 else if (rc == ERROR_INSTALL_USEREXIT)
998 ACTION_PerformActionSequence(package,-2,ui);
999 else if (rc == ERROR_FUNCTION_FAILED)
1000 ACTION_PerformActionSequence(package,-3,ui);
1001 else if (rc == ERROR_INSTALL_SUSPEND)
1002 ACTION_PerformActionSequence(package,-4,ui);
1004 /* finish up running custom actions */
1005 ACTION_FinishCustomActions(package);
1010 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
1014 WCHAR buffer[0x100];
1016 MSIRECORD * row = 0;
1017 static const WCHAR ExecSeqQuery[] =
1018 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1019 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1020 'S','e','q','u','e','n','c','e',' ', 'W','H','E','R','E',' ',
1021 'S','e','q','u','e','n','c','e',' ', '=',' ','%','i',0};
1023 static const WCHAR UISeqQuery[] =
1024 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1025 'I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
1026 ' ', 'W','H','E','R','E',' ', 'S','e','q','u','e','n','c','e',
1027 ' ', '=',' ','%','i',0};
1030 rc = MSI_OpenQuery(package->db, &view, UISeqQuery, seq);
1032 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
1034 if (rc == ERROR_SUCCESS)
1036 rc = MSI_ViewExecute(view, 0);
1038 if (rc != ERROR_SUCCESS)
1040 MSI_ViewClose(view);
1041 msiobj_release(&view->hdr);
1045 TRACE("Running the actions\n");
1047 rc = MSI_ViewFetch(view,&row);
1048 if (rc != ERROR_SUCCESS)
1054 /* check conditions */
1055 if (!MSI_RecordIsNull(row,2))
1058 cond = load_dynamic_stringW(row,2);
1062 /* this is a hack to skip errors in the condition code */
1063 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
1065 HeapFree(GetProcessHeap(),0,cond);
1066 msiobj_release(&row->hdr);
1070 HeapFree(GetProcessHeap(),0,cond);
1075 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
1076 if (rc != ERROR_SUCCESS)
1078 ERR("Error is %x\n",rc);
1079 msiobj_release(&row->hdr);
1084 rc = ACTION_PerformUIAction(package,buffer);
1086 rc = ACTION_PerformAction(package,buffer);
1087 msiobj_release(&row->hdr);
1089 MSI_ViewClose(view);
1090 msiobj_release(&view->hdr);
1098 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
1102 static const WCHAR ExecSeqQuery[] =
1103 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1104 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1105 'S','e','q','u','e','n','c','e',' ', 'W','H','E','R','E',' ',
1106 'S','e','q','u','e','n','c','e',' ', '>',' ','%','i',' ',
1107 'O','R','D','E','R',' ', 'B','Y',' ',
1108 'S','e','q','u','e','n','c','e',0 };
1109 MSIRECORD * row = 0;
1110 static const WCHAR IVQuery[] =
1111 {'S','E','L','E','C','T',' ','S','e','q','u','e','n','c','e',' ',
1112 'F','R','O','M',' ','I','n','s','t','a','l','l',
1113 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e',' ',
1114 'W','H','E','R','E',' ','A','c','t','i','o','n',' ','=',' ','`',
1115 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`', 0};
1119 if (package->ExecuteSequenceRun)
1121 TRACE("Execute Sequence already Run\n");
1122 return ERROR_SUCCESS;
1125 package->ExecuteSequenceRun = TRUE;
1127 /* get the sequence number */
1130 rc = MSI_DatabaseOpenViewW(package->db, IVQuery, &view);
1131 if (rc != ERROR_SUCCESS)
1133 rc = MSI_ViewExecute(view, 0);
1134 if (rc != ERROR_SUCCESS)
1136 MSI_ViewClose(view);
1137 msiobj_release(&view->hdr);
1140 rc = MSI_ViewFetch(view,&row);
1141 if (rc != ERROR_SUCCESS)
1143 MSI_ViewClose(view);
1144 msiobj_release(&view->hdr);
1147 seq = MSI_RecordGetInteger(row,1);
1148 msiobj_release(&row->hdr);
1149 MSI_ViewClose(view);
1150 msiobj_release(&view->hdr);
1153 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
1154 if (rc == ERROR_SUCCESS)
1156 rc = MSI_ViewExecute(view, 0);
1158 if (rc != ERROR_SUCCESS)
1160 MSI_ViewClose(view);
1161 msiobj_release(&view->hdr);
1165 TRACE("Running the actions\n");
1169 WCHAR buffer[0x100];
1172 rc = MSI_ViewFetch(view,&row);
1173 if (rc != ERROR_SUCCESS)
1179 /* check conditions */
1180 if (!MSI_RecordIsNull(row,2))
1183 cond = load_dynamic_stringW(row,2);
1187 /* this is a hack to skip errors in the condition code */
1188 if (MSI_EvaluateConditionW(package, cond) ==
1191 HeapFree(GetProcessHeap(),0,cond);
1192 msiobj_release(&row->hdr);
1196 HeapFree(GetProcessHeap(),0,cond);
1201 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
1202 if (rc != ERROR_SUCCESS)
1204 ERR("Error is %x\n",rc);
1205 msiobj_release(&row->hdr);
1209 rc = ACTION_PerformAction(package,buffer);
1211 if (rc == ERROR_FUNCTION_NOT_CALLED)
1214 if (rc != ERROR_SUCCESS)
1216 ERR("Execution halted due to error (%i)\n",rc);
1217 msiobj_release(&row->hdr);
1221 msiobj_release(&row->hdr);
1224 MSI_ViewClose(view);
1225 msiobj_release(&view->hdr);
1233 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1237 static const WCHAR ExecSeqQuery [] =
1238 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1239 'I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
1240 ' ','W','H','E','R','E',' ', 'S','e','q','u','e','n','c','e',' ',
1241 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1242 'S','e','q','u','e','n','c','e',0};
1244 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
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];
1263 MSIRECORD * row = 0;
1265 rc = MSI_ViewFetch(view,&row);
1266 if (rc != ERROR_SUCCESS)
1272 /* check conditions */
1273 if (!MSI_RecordIsNull(row,2))
1276 cond = load_dynamic_stringW(row,2);
1280 /* this is a hack to skip errors in the condition code */
1281 if (MSI_EvaluateConditionW(package, cond) ==
1284 HeapFree(GetProcessHeap(),0,cond);
1285 msiobj_release(&row->hdr);
1289 HeapFree(GetProcessHeap(),0,cond);
1294 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
1295 if (rc != ERROR_SUCCESS)
1297 ERR("Error is %x\n",rc);
1298 msiobj_release(&row->hdr);
1302 rc = ACTION_PerformUIAction(package,buffer);
1304 if (rc == ERROR_FUNCTION_NOT_CALLED)
1307 if (rc != ERROR_SUCCESS)
1309 ERR("Execution halted due to error (%i)\n",rc);
1310 msiobj_release(&row->hdr);
1314 msiobj_release(&row->hdr);
1317 MSI_ViewClose(view);
1318 msiobj_release(&view->hdr);
1325 /********************************************************
1326 * ACTION helper functions and functions that perform the actions
1327 *******************************************************/
1328 BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc)
1334 while (StandardActions[i].action != NULL)
1336 if (strcmpW(StandardActions[i].action, action)==0)
1338 ui_actioninfo(package, action, TRUE, 0);
1339 ui_actionstart(package, action);
1340 if (StandardActions[i].handler)
1342 *rc = StandardActions[i].handler(package);
1346 FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action));
1347 *rc = ERROR_SUCCESS;
1349 ui_actioninfo(package, action, FALSE, *rc);
1358 BOOL ACTION_HandleDialogBox(MSIPACKAGE *package, LPCWSTR dialog, UINT* rc)
1363 * for the UI when we get that working
1365 if (ACTION_DialogBox(package,dialog) == ERROR_SUCCESS)
1367 *rc = package->CurrentInstallState;
1374 BOOL ACTION_HandleCustomAction(MSIPACKAGE* package, LPCWSTR action, UINT* rc)
1379 arc = ACTION_CustomAction(package,action,FALSE);
1381 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1390 * A lot of actions are really important even if they don't do anything
1391 * explicit... Lots of properties are set at the beginning of the installation
1392 * CostFinalize does a bunch of work to translate the directories and such
1394 * But until I get write access to the database that is hard, so I am going to
1395 * hack it to see if I can get something to run.
1397 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action)
1399 UINT rc = ERROR_SUCCESS;
1402 TRACE("Performing action (%s)\n",debugstr_w(action));
1404 handled = ACTION_HandleStandardAction(package, action, &rc);
1407 handled = ACTION_HandleCustomAction(package, action, &rc);
1411 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
1412 rc = ERROR_FUNCTION_NOT_CALLED;
1415 package->CurrentInstallState = rc;
1419 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
1421 UINT rc = ERROR_SUCCESS;
1422 BOOL handled = FALSE;
1424 TRACE("Performing action (%s)\n",debugstr_w(action));
1426 handled = ACTION_HandleStandardAction(package, action, &rc);
1429 handled = ACTION_HandleCustomAction(package, action, &rc);
1432 handled = ACTION_HandleDialogBox(package, action, &rc);
1434 msi_dialog_check_messages( NULL );
1438 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
1439 rc = ERROR_FUNCTION_NOT_CALLED;
1442 package->CurrentInstallState = rc;
1446 /***********************************************************************
1449 * Recursively create all directories in the path.
1451 * shamelessly stolen from setupapi/queue.c
1453 static BOOL create_full_pathW(const WCHAR *path)
1459 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *
1462 strcpyW(new_path, path);
1464 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
1465 new_path[len - 1] = 0;
1467 while(!CreateDirectoryW(new_path, NULL))
1470 DWORD last_error = GetLastError();
1471 if(last_error == ERROR_ALREADY_EXISTS)
1474 if(last_error != ERROR_PATH_NOT_FOUND)
1480 if(!(slash = strrchrW(new_path, '\\')))
1486 len = slash - new_path;
1488 if(!create_full_pathW(new_path))
1493 new_path[len] = '\\';
1496 HeapFree(GetProcessHeap(), 0, new_path);
1501 * Also we cannot enable/disable components either, so for now I am just going
1502 * to do all the directories for all the components.
1504 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1506 static const WCHAR ExecSeqQuery[] =
1507 {'S','E','L','E','C','T',' ','D','i','r','e','c','t','o','r','y','_',
1508 ' ','F','R','O','M',' ',
1509 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
1514 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1515 if (rc != ERROR_SUCCESS)
1516 return ERROR_SUCCESS;
1518 rc = MSI_ViewExecute(view, 0);
1519 if (rc != ERROR_SUCCESS)
1521 MSI_ViewClose(view);
1522 msiobj_release(&view->hdr);
1531 MSIRECORD *row = NULL, *uirow;
1533 rc = MSI_ViewFetch(view,&row);
1534 if (rc != ERROR_SUCCESS)
1541 rc = MSI_RecordGetStringW(row,1,dir,&sz);
1543 if (rc!= ERROR_SUCCESS)
1545 ERR("Unable to get folder id \n");
1546 msiobj_release(&row->hdr);
1551 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1554 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1555 msiobj_release(&row->hdr);
1559 TRACE("Folder is %s\n",debugstr_w(full_path));
1562 uirow = MSI_CreateRecord(1);
1563 MSI_RecordSetStringW(uirow,1,full_path);
1564 ui_actiondata(package,szCreateFolders,uirow);
1565 msiobj_release( &uirow->hdr );
1567 if (folder->State == 0)
1568 create_full_pathW(full_path);
1572 msiobj_release(&row->hdr);
1573 HeapFree(GetProcessHeap(),0,full_path);
1575 MSI_ViewClose(view);
1576 msiobj_release(&view->hdr);
1581 static int load_component(MSIPACKAGE* package, MSIRECORD * row)
1583 int index = package->loaded_components;
1586 /* fill in the data */
1588 package->loaded_components++;
1589 if (package->loaded_components == 1)
1590 package->components = HeapAlloc(GetProcessHeap(),0,
1591 sizeof(MSICOMPONENT));
1593 package->components = HeapReAlloc(GetProcessHeap(),0,
1594 package->components, package->loaded_components *
1595 sizeof(MSICOMPONENT));
1597 memset(&package->components[index],0,sizeof(MSICOMPONENT));
1600 MSI_RecordGetStringW(row,1,package->components[index].Component,&sz);
1602 TRACE("Loading Component %s\n",
1603 debugstr_w(package->components[index].Component));
1606 if (!MSI_RecordIsNull(row,2))
1607 MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz);
1610 MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz);
1612 package->components[index].Attributes = MSI_RecordGetInteger(row,4);
1615 MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz);
1618 MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);
1620 package->components[index].Installed = INSTALLSTATE_ABSENT;
1621 package->components[index].Action = INSTALLSTATE_UNKNOWN;
1622 package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN;
1624 package->components[index].Enabled = TRUE;
1629 static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
1631 int index = package->loaded_features;
1633 static const WCHAR Query1[] =
1634 {'S','E','L','E','C','T',' ','C','o','m','p','o','n','e','n','t','_',
1635 ' ','F','R','O','M',' ','F','e','a','t','u','r','e',
1636 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ',
1637 'F','e', 'a','t','u','r','e','_','=','\'','%','s','\'',0};
1638 static const WCHAR Query2[] =
1639 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1640 'C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ',
1641 'C','o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};
1648 /* fill in the data */
1650 package->loaded_features ++;
1651 if (package->loaded_features == 1)
1652 package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE));
1654 package->features = HeapReAlloc(GetProcessHeap(),0,package->features,
1655 package->loaded_features * sizeof(MSIFEATURE));
1657 memset(&package->features[index],0,sizeof(MSIFEATURE));
1660 MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz);
1662 TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature));
1665 if (!MSI_RecordIsNull(row,2))
1666 MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz);
1669 if (!MSI_RecordIsNull(row,3))
1670 MSI_RecordGetStringW(row,3,package->features[index].Title,&sz);
1673 if (!MSI_RecordIsNull(row,4))
1674 MSI_RecordGetStringW(row,4,package->features[index].Description,&sz);
1676 if (!MSI_RecordIsNull(row,5))
1677 package->features[index].Display = MSI_RecordGetInteger(row,5);
1679 package->features[index].Level= MSI_RecordGetInteger(row,6);
1682 if (!MSI_RecordIsNull(row,7))
1683 MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);
1685 package->features[index].Attributes= MSI_RecordGetInteger(row,8);
1687 package->features[index].Installed = INSTALLSTATE_ABSENT;
1688 package->features[index].Action = INSTALLSTATE_UNKNOWN;
1689 package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN;
1691 /* load feature components */
1693 rc = MSI_OpenQuery(package->db, &view, Query1, package->features[index].Feature);
1694 if (rc != ERROR_SUCCESS)
1696 rc = MSI_ViewExecute(view,0);
1697 if (rc != ERROR_SUCCESS)
1699 MSI_ViewClose(view);
1700 msiobj_release(&view->hdr);
1706 WCHAR buffer[0x100];
1709 INT cnt = package->features[index].ComponentCount;
1711 rc = MSI_ViewFetch(view,&row2);
1712 if (rc != ERROR_SUCCESS)
1716 MSI_RecordGetStringW(row2,1,buffer,&sz);
1718 /* check to see if the component is already loaded */
1719 c_indx = get_loaded_component(package,buffer);
1722 TRACE("Component %s already loaded at %i\n", debugstr_w(buffer),
1724 package->features[index].Components[cnt] = c_indx;
1725 package->features[index].ComponentCount ++;
1726 msiobj_release( &row2->hdr );
1730 rc = MSI_OpenQuery(package->db, &view2, Query2, buffer);
1731 if (rc != ERROR_SUCCESS)
1733 msiobj_release( &row2->hdr );
1736 rc = MSI_ViewExecute(view2,0);
1737 if (rc != ERROR_SUCCESS)
1739 msiobj_release( &row2->hdr );
1740 MSI_ViewClose(view2);
1741 msiobj_release( &view2->hdr );
1748 rc = MSI_ViewFetch(view2,&row3);
1749 if (rc != ERROR_SUCCESS)
1751 c_indx = load_component(package,row3);
1752 msiobj_release( &row3->hdr );
1754 package->features[index].Components[cnt] = c_indx;
1755 package->features[index].ComponentCount ++;
1756 TRACE("Loaded new component to index %i\n",c_indx);
1758 MSI_ViewClose(view2);
1759 msiobj_release( &view2->hdr );
1760 msiobj_release( &row2->hdr );
1762 MSI_ViewClose(view);
1763 msiobj_release(&view->hdr);
1766 static UINT load_file(MSIPACKAGE* package, MSIRECORD * row)
1768 DWORD index = package->loaded_files;
1772 /* fill in the data */
1774 package->loaded_files++;
1775 if (package->loaded_files== 1)
1776 package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
1778 package->files = HeapReAlloc(GetProcessHeap(),0,
1779 package->files , package->loaded_files * sizeof(MSIFILE));
1781 memset(&package->files[index],0,sizeof(MSIFILE));
1783 package->files[index].File = load_dynamic_stringW(row, 1);
1784 buffer = load_dynamic_stringW(row, 2);
1786 package->files[index].ComponentIndex = -1;
1787 for (i = 0; i < package->loaded_components; i++)
1788 if (strcmpW(package->components[i].Component,buffer)==0)
1790 package->files[index].ComponentIndex = i;
1793 if (package->files[index].ComponentIndex == -1)
1794 ERR("Unfound Component %s\n",debugstr_w(buffer));
1795 HeapFree(GetProcessHeap(), 0, buffer);
1797 package->files[index].FileName = load_dynamic_stringW(row,3);
1798 reduce_to_longfilename(package->files[index].FileName);
1800 package->files[index].ShortName = load_dynamic_stringW(row,3);
1801 reduce_to_shortfilename(package->files[index].ShortName);
1803 package->files[index].FileSize = MSI_RecordGetInteger(row,4);
1804 package->files[index].Version = load_dynamic_stringW(row, 5);
1805 package->files[index].Language = load_dynamic_stringW(row, 6);
1806 package->files[index].Attributes= MSI_RecordGetInteger(row,7);
1807 package->files[index].Sequence= MSI_RecordGetInteger(row,8);
1809 package->files[index].Temporary = FALSE;
1810 package->files[index].State = 0;
1812 TRACE("File Loaded (%s)\n",debugstr_w(package->files[index].File));
1814 return ERROR_SUCCESS;
1817 static UINT load_all_files(MSIPACKAGE *package)
1822 static const WCHAR Query[] =
1823 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1824 'F','i','l','e',' ', 'O','R','D','E','R',' ','B','Y',' ',
1825 'S','e','q','u','e','n','c','e', 0};
1828 return ERROR_INVALID_HANDLE;
1830 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1831 if (rc != ERROR_SUCCESS)
1832 return ERROR_SUCCESS;
1834 rc = MSI_ViewExecute(view, 0);
1835 if (rc != ERROR_SUCCESS)
1837 MSI_ViewClose(view);
1838 msiobj_release(&view->hdr);
1839 return ERROR_SUCCESS;
1844 rc = MSI_ViewFetch(view,&row);
1845 if (rc != ERROR_SUCCESS)
1850 load_file(package,row);
1851 msiobj_release(&row->hdr);
1853 MSI_ViewClose(view);
1854 msiobj_release(&view->hdr);
1856 return ERROR_SUCCESS;
1861 * I am not doing any of the costing functionality yet.
1862 * Mostly looking at doing the Component and Feature loading
1864 * The native MSI does A LOT of modification to tables here. Mostly adding
1865 * a lot of temporary columns to the Feature and Component tables.
1867 * note: Native msi also tracks the short filename. But I am only going to
1868 * track the long ones. Also looking at this directory table
1869 * it appears that the directory table does not get the parents
1870 * resolved base on property only based on their entries in the
1873 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1878 static const WCHAR Query_all[] =
1879 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1880 'F','e','a','t','u','r','e',0};
1881 static const WCHAR szCosting[] =
1882 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1883 static const WCHAR szZero[] = { '0', 0 };
1887 MSI_GetPropertyW(package, szCosting, buffer, &sz);
1889 return ERROR_SUCCESS;
1891 MSI_SetPropertyW(package, szCosting, szZero);
1892 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1894 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1895 if (rc != ERROR_SUCCESS)
1897 rc = MSI_ViewExecute(view,0);
1898 if (rc != ERROR_SUCCESS)
1900 MSI_ViewClose(view);
1901 msiobj_release(&view->hdr);
1908 rc = MSI_ViewFetch(view,&row);
1909 if (rc != ERROR_SUCCESS)
1912 load_feature(package,row);
1913 msiobj_release(&row->hdr);
1915 MSI_ViewClose(view);
1916 msiobj_release(&view->hdr);
1918 load_all_files(package);
1920 return ERROR_SUCCESS;
1923 static UINT ACTION_FileCost(MSIPACKAGE *package)
1925 return ERROR_SUCCESS;
1929 static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)
1931 static const WCHAR Query[] =
1932 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1933 'D','i','r','e','c', 't','o','r','y',' ','W','H','E','R','E',' ','`',
1934 'D','i','r','e','c','t', 'o','r','y','`',' ','=',' ','`','%','s','`',
1938 LPWSTR ptargetdir, targetdir, parent, srcdir;
1939 LPWSTR shortname = NULL;
1940 MSIRECORD * row = 0;
1944 TRACE("Looking for dir %s\n",debugstr_w(dir));
1946 for (i = 0; i < package->loaded_folders; i++)
1948 if (strcmpW(package->folders[i].Directory,dir)==0)
1950 TRACE(" %s retuning on index %lu\n",debugstr_w(dir),i);
1955 TRACE("Working to load %s\n",debugstr_w(dir));
1957 index = package->loaded_folders++;
1958 if (package->loaded_folders==1)
1959 package->folders = HeapAlloc(GetProcessHeap(),0,
1962 package->folders= HeapReAlloc(GetProcessHeap(),0,
1963 package->folders, package->loaded_folders*
1966 memset(&package->folders[index],0,sizeof(MSIFOLDER));
1968 package->folders[index].Directory = strdupW(dir);
1970 rc = MSI_OpenQuery(package->db, &view, Query, dir);
1971 if (rc != ERROR_SUCCESS)
1974 rc = MSI_ViewExecute(view, 0);
1975 if (rc != ERROR_SUCCESS)
1977 MSI_ViewClose(view);
1978 msiobj_release(&view->hdr);
1982 rc = MSI_ViewFetch(view,&row);
1983 if (rc != ERROR_SUCCESS)
1985 MSI_ViewClose(view);
1986 msiobj_release(&view->hdr);
1990 ptargetdir = targetdir = load_dynamic_stringW(row,3);
1992 /* split src and target dir */
1993 if (strchrW(targetdir,':'))
1995 srcdir=strchrW(targetdir,':');
2002 /* for now only pick long filename versions */
2003 if (strchrW(targetdir,'|'))
2005 shortname = targetdir;
2006 targetdir = strchrW(targetdir,'|');
2010 /* for the sourcedir pick the short filename */
2011 if (srcdir && strchrW(srcdir,'|'))
2013 LPWSTR p = strchrW(srcdir,'|');
2017 /* now check for root dirs */
2018 if (targetdir[0] == '.' && targetdir[1] == 0)
2021 if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
2026 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
2027 HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault);
2028 package->folders[index].TargetDefault = strdupW(targetdir);
2032 package->folders[index].SourceDefault = strdupW(srcdir);
2034 package->folders[index].SourceDefault = strdupW(shortname);
2036 package->folders[index].SourceDefault = strdupW(targetdir);
2037 HeapFree(GetProcessHeap(), 0, ptargetdir);
2038 TRACE(" SourceDefault = %s\n",debugstr_w(package->folders[index].SourceDefault));
2040 parent = load_dynamic_stringW(row,2);
2043 i = load_folder(package,parent);
2044 package->folders[index].ParentIndex = i;
2045 TRACE("Parent is index %i... %s %s\n",
2046 package->folders[index].ParentIndex,
2047 debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),
2048 debugstr_w(parent));
2051 package->folders[index].ParentIndex = -2;
2052 HeapFree(GetProcessHeap(), 0, parent);
2054 package->folders[index].Property = load_dynamic_property(package, dir,NULL);
2056 msiobj_release(&row->hdr);
2057 MSI_ViewClose(view);
2058 msiobj_release(&view->hdr);
2059 TRACE(" %s retuning on index %i\n",debugstr_w(dir),index);
2064 LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
2065 BOOL set_prop, MSIFOLDER **folder)
2068 LPWSTR p, path = NULL;
2070 TRACE("Working to resolve %s\n",debugstr_w(name));
2072 /* special resolving for Target and Source root dir */
2073 if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
2077 path = load_dynamic_property(package,cszTargetDir,NULL);
2080 path = load_dynamic_property(package,cszRootDrive,NULL);
2082 MSI_SetPropertyW(package,cszTargetDir,path);
2086 for (i = 0; i < package->loaded_folders; i++)
2088 if (strcmpW(package->folders[i].Directory,name)==0)
2091 *folder = &(package->folders[i]);
2097 path = load_dynamic_property(package,cszSourceDir,NULL);
2100 path = load_dynamic_property(package,cszDatabase,NULL);
2103 p = strrchrW(path,'\\');
2110 for (i = 0; i < package->loaded_folders; i++)
2112 if (strcmpW(package->folders[i].Directory,name)==0)
2115 *folder = &(package->folders[i]);
2121 for (i = 0; i < package->loaded_folders; i++)
2123 if (strcmpW(package->folders[i].Directory,name)==0)
2127 if (i >= package->loaded_folders)
2131 *folder = &(package->folders[i]);
2133 if (!source && package->folders[i].ResolvedTarget)
2135 path = strdupW(package->folders[i].ResolvedTarget);
2136 TRACE(" already resolved to %s\n",debugstr_w(path));
2139 else if (source && package->folders[i].ResolvedSource)
2141 path = strdupW(package->folders[i].ResolvedSource);
2142 TRACE(" (source)already resolved to %s\n",debugstr_w(path));
2145 else if (!source && package->folders[i].Property)
2147 path = build_directory_name(2, package->folders[i].Property, NULL);
2149 TRACE(" internally set to %s\n",debugstr_w(path));
2151 MSI_SetPropertyW(package,name,path);
2155 if (package->folders[i].ParentIndex >= 0)
2157 LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;
2159 TRACE(" ! Parent is %s\n", debugstr_w(parent));
2161 p = resolve_folder(package, parent, source, set_prop, NULL);
2164 TRACE(" TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault));
2165 path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL);
2166 package->folders[i].ResolvedTarget = strdupW(path);
2167 TRACE(" resolved into %s\n",debugstr_w(path));
2169 MSI_SetPropertyW(package,name,path);
2173 path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);
2174 TRACE(" (source)resolved into %s\n",debugstr_w(path));
2175 package->folders[i].ResolvedSource = strdupW(path);
2177 HeapFree(GetProcessHeap(),0,p);
2182 /* scan for and update current install states */
2183 void ACTION_UpdateInstallStates(MSIPACKAGE *package)
2188 productcode = load_dynamic_property(package,szProductCode,NULL);
2190 for (i = 0; i < package->loaded_components; i++)
2193 res = MsiGetComponentPathW(productcode,
2194 package->components[i].ComponentId , NULL, NULL);
2196 res = INSTALLSTATE_ABSENT;
2197 package->components[i].Installed = res;
2200 for (i = 0; i < package->loaded_features; i++)
2202 INSTALLSTATE res = -10;
2204 for (j = 0; j < package->features[i].ComponentCount; j++)
2206 MSICOMPONENT* component = &package->components[package->features[i].
2209 res = component->Installed;
2212 if (res == component->Installed)
2215 if (res != component->Installed)
2216 res = INSTALLSTATE_INCOMPLETE;
2222 /* update compoennt state based on a feature change */
2223 void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
2226 INSTALLSTATE newstate;
2227 MSIFEATURE *feature;
2229 i = get_loaded_feature(package,szFeature);
2233 feature = &package->features[i];
2234 newstate = feature->ActionRequest;
2236 for( i = 0; i < feature->ComponentCount; i++)
2238 MSICOMPONENT* component = &package->components[feature->Components[i]];
2240 TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n",
2241 newstate, debugstr_w(component->Component), component->Installed,
2242 component->Action, component->ActionRequest);
2244 if (!component->Enabled)
2248 if (newstate == INSTALLSTATE_LOCAL)
2250 component->ActionRequest = INSTALLSTATE_LOCAL;
2251 component->Action = INSTALLSTATE_LOCAL;
2257 component->ActionRequest = newstate;
2258 component->Action = newstate;
2260 /*if any other feature wants is local we need to set it local*/
2262 j < package->loaded_features &&
2263 component->ActionRequest != INSTALLSTATE_LOCAL;
2266 for (k = 0; k < package->features[j].ComponentCount; k++)
2267 if ( package->features[j].Components[k] ==
2268 feature->Components[i] )
2270 if (package->features[j].ActionRequest ==
2273 TRACE("Saved by %s\n", debugstr_w(package->features[j].Feature));
2274 component->ActionRequest = INSTALLSTATE_LOCAL;
2275 component->Action = INSTALLSTATE_LOCAL;
2282 TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n",
2283 newstate, debugstr_w(component->Component), component->Installed,
2284 component->Action, component->ActionRequest);
2288 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
2291 static const WCHAR all[]={'A','L','L',0};
2292 LPWSTR override = NULL;
2296 override = load_dynamic_property(package, property, NULL);
2300 for(i = 0; i < package->loaded_features; i++)
2302 if (strcmpiW(override,all)==0)
2304 package->features[i].ActionRequest= state;
2305 package->features[i].Action = state;
2309 LPWSTR ptr = override;
2310 LPWSTR ptr2 = strchrW(override,',');
2315 strncmpW(ptr,package->features[i].Feature, ptr2-ptr)==0)
2317 strcmpW(ptr,package->features[i].Feature)==0))
2319 package->features[i].ActionRequest= state;
2320 package->features[i].Action = state;
2326 ptr2 = strchrW(ptr,',');
2333 HeapFree(GetProcessHeap(),0,override);
2339 static UINT SetFeatureStates(MSIPACKAGE *package)
2345 static const WCHAR szlevel[] =
2346 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2347 static const WCHAR szAddLocal[] =
2348 {'A','D','D','L','O','C','A','L',0};
2349 static const WCHAR szRemove[] =
2350 {'R','E','M','O','V','E',0};
2351 BOOL override = FALSE;
2353 /* I do not know if this is where it should happen.. but */
2355 TRACE("Checking Install Level\n");
2357 level = load_dynamic_property(package,szlevel,NULL);
2360 install_level = atoiW(level);
2361 HeapFree(GetProcessHeap(), 0, level);
2366 /* ok hereis the _real_ rub
2367 * all these activation/deactivation things happen in order and things
2368 * later on the list override things earlier on the list.
2369 * 1) INSTALLLEVEL processing
2379 * 11) FILEADDDEFAULT
2380 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
2381 * ignored for all the features. seems strange, especially since it is not
2382 * documented anywhere, but it is how it works.
2384 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
2385 * REMOVE are the big ones, since we don't handle administrative installs
2388 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
2389 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
2393 for(i = 0; i < package->loaded_features; i++)
2395 BOOL feature_state = ((package->features[i].Level > 0) &&
2396 (package->features[i].Level <= install_level));
2398 if ((feature_state) &&
2399 (package->features[i].Action == INSTALLSTATE_UNKNOWN))
2401 if (package->features[i].Attributes &
2402 msidbFeatureAttributesFavorSource)
2404 package->features[i].ActionRequest = INSTALLSTATE_SOURCE;
2405 package->features[i].Action = INSTALLSTATE_SOURCE;
2407 else if (package->features[i].Attributes &
2408 msidbFeatureAttributesFavorAdvertise)
2410 package->features[i].ActionRequest =INSTALLSTATE_ADVERTISED;
2411 package->features[i].Action =INSTALLSTATE_ADVERTISED;
2415 package->features[i].ActionRequest = INSTALLSTATE_LOCAL;
2416 package->features[i].Action = INSTALLSTATE_LOCAL;
2423 * now we want to enable or disable components base on feature
2426 for(i = 0; i < package->loaded_features; i++)
2428 MSIFEATURE* feature = &package->features[i];
2429 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
2430 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2431 feature->ActionRequest);
2433 for( j = 0; j < feature->ComponentCount; j++)
2435 MSICOMPONENT* component = &package->components[
2436 feature->Components[j]];
2438 if (!component->Enabled)
2440 component->Action = INSTALLSTATE_UNKNOWN;
2441 component->ActionRequest = INSTALLSTATE_UNKNOWN;
2445 if (feature->Action == INSTALLSTATE_LOCAL)
2447 component->Action = INSTALLSTATE_LOCAL;
2448 component->ActionRequest = INSTALLSTATE_LOCAL;
2450 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
2452 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
2453 (component->Action == INSTALLSTATE_ABSENT) ||
2454 (component->Action == INSTALLSTATE_ADVERTISED))
2457 component->Action = INSTALLSTATE_SOURCE;
2458 component->ActionRequest = INSTALLSTATE_SOURCE;
2461 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
2463 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
2464 (component->Action == INSTALLSTATE_ABSENT))
2467 component->Action = INSTALLSTATE_ADVERTISED;
2468 component->ActionRequest = INSTALLSTATE_ADVERTISED;
2471 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
2473 if (component->Action == INSTALLSTATE_UNKNOWN)
2475 component->Action = INSTALLSTATE_ABSENT;
2476 component->ActionRequest = INSTALLSTATE_ABSENT;
2483 for(i = 0; i < package->loaded_components; i++)
2485 MSICOMPONENT* component= &package->components[i];
2487 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
2488 debugstr_w(component->Component), component->Installed,
2489 component->Action, component->ActionRequest);
2493 return ERROR_SUCCESS;
2497 * A lot is done in this function aside from just the costing.
2498 * The costing needs to be implemented at some point but for now I am going
2499 * to focus on the directory building
2502 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2504 static const WCHAR ExecSeqQuery[] =
2505 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2506 'D','i','r','e','c','t','o','r','y',0};
2507 static const WCHAR ConditionQuery[] =
2508 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2509 'C','o','n','d','i','t','i','o','n',0};
2510 static const WCHAR szCosting[] =
2511 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2512 static const WCHAR szlevel[] =
2513 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2514 static const WCHAR szOne[] = { '1', 0 };
2522 MSI_GetPropertyW(package, szCosting, buffer, &sz);
2524 return ERROR_SUCCESS;
2526 TRACE("Building Directory properties\n");
2528 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2529 if (rc == ERROR_SUCCESS)
2531 rc = MSI_ViewExecute(view, 0);
2532 if (rc != ERROR_SUCCESS)
2534 MSI_ViewClose(view);
2535 msiobj_release(&view->hdr);
2543 MSIRECORD * row = 0;
2546 rc = MSI_ViewFetch(view,&row);
2547 if (rc != ERROR_SUCCESS)
2554 MSI_RecordGetStringW(row,1,name,&sz);
2556 /* This helper function now does ALL the work */
2557 TRACE("Dir %s ...\n",debugstr_w(name));
2558 load_folder(package,name);
2559 path = resolve_folder(package,name,FALSE,TRUE,NULL);
2560 TRACE("resolves to %s\n",debugstr_w(path));
2561 HeapFree( GetProcessHeap(), 0, path);
2563 msiobj_release(&row->hdr);
2565 MSI_ViewClose(view);
2566 msiobj_release(&view->hdr);
2569 TRACE("File calculations %i files\n",package->loaded_files);
2571 for (i = 0; i < package->loaded_files; i++)
2573 MSICOMPONENT* comp = NULL;
2574 MSIFILE* file= NULL;
2576 file = &package->files[i];
2577 if (file->ComponentIndex >= 0)
2578 comp = &package->components[file->ComponentIndex];
2580 if (file->Temporary == TRUE)
2587 /* calculate target */
2588 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
2590 HeapFree(GetProcessHeap(),0,file->TargetPath);
2592 TRACE("file %s is named %s\n",
2593 debugstr_w(file->File),debugstr_w(file->FileName));
2595 file->TargetPath = build_directory_name(2, p, file->FileName);
2597 HeapFree(GetProcessHeap(),0,p);
2599 TRACE("file %s resolves to %s\n",
2600 debugstr_w(file->File),debugstr_w(file->TargetPath));
2602 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2605 comp->Cost += file->FileSize;
2615 static const WCHAR name[] =
2617 static const WCHAR name_fmt[] =
2618 {'%','u','.','%','u','.','%','u','.','%','u',0};
2619 WCHAR filever[0x100];
2620 VS_FIXEDFILEINFO *lpVer;
2622 TRACE("Version comparison.. \n");
2623 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
2624 version = HeapAlloc(GetProcessHeap(),0,versize);
2625 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
2627 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
2629 sprintfW(filever,name_fmt,
2630 HIWORD(lpVer->dwFileVersionMS),
2631 LOWORD(lpVer->dwFileVersionMS),
2632 HIWORD(lpVer->dwFileVersionLS),
2633 LOWORD(lpVer->dwFileVersionLS));
2635 TRACE("new %s old %s\n", debugstr_w(file->Version),
2636 debugstr_w(filever));
2637 if (strcmpiW(filever,file->Version)<0)
2640 FIXME("cost should be diff in size\n");
2641 comp->Cost += file->FileSize;
2645 HeapFree(GetProcessHeap(),0,version);
2653 TRACE("Evaluating Condition Table\n");
2655 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2656 if (rc == ERROR_SUCCESS)
2658 rc = MSI_ViewExecute(view, 0);
2659 if (rc != ERROR_SUCCESS)
2661 MSI_ViewClose(view);
2662 msiobj_release(&view->hdr);
2668 WCHAR Feature[0x100];
2669 MSIRECORD * row = 0;
2673 rc = MSI_ViewFetch(view,&row);
2675 if (rc != ERROR_SUCCESS)
2682 MSI_RecordGetStringW(row,1,Feature,&sz);
2684 feature_index = get_loaded_feature(package,Feature);
2685 if (feature_index < 0)
2686 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));
2690 Condition = load_dynamic_stringW(row,3);
2692 if (MSI_EvaluateConditionW(package,Condition) ==
2695 int level = MSI_RecordGetInteger(row,2);
2696 TRACE("Reseting feature %s to level %i\n",
2697 debugstr_w(Feature), level);
2698 package->features[feature_index].Level = level;
2700 HeapFree(GetProcessHeap(),0,Condition);
2703 msiobj_release(&row->hdr);
2705 MSI_ViewClose(view);
2706 msiobj_release(&view->hdr);
2709 TRACE("Enabling or Disabling Components\n");
2710 for (i = 0; i < package->loaded_components; i++)
2712 if (package->components[i].Condition[0])
2714 if (MSI_EvaluateConditionW(package,
2715 package->components[i].Condition) == MSICONDITION_FALSE)
2717 TRACE("Disabling component %s\n",
2718 debugstr_w(package->components[i].Component));
2719 package->components[i].Enabled = FALSE;
2724 MSI_SetPropertyW(package,szCosting,szOne);
2725 /* set default run level if not set */
2726 level = load_dynamic_property(package,szlevel,NULL);
2728 MSI_SetPropertyW(package,szlevel, szOne);
2730 HeapFree(GetProcessHeap(),0,level);
2732 ACTION_UpdateInstallStates(package);
2734 return SetFeatureStates(package);
2738 * This is a helper function for handling embedded cabinet media
2740 static UINT writeout_cabinet_stream(MSIPACKAGE *package, WCHAR* stream_name,
2748 WCHAR tmp[MAX_PATH];
2750 rc = read_raw_stream_data(package->db,stream_name,&data,&size);
2751 if (rc != ERROR_SUCCESS)
2755 if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
2756 GetTempPathW(MAX_PATH,tmp);
2758 GetTempFileNameW(tmp,stream_name,0,source);
2760 track_tempfile(package,strrchrW(source,'\\'), source);
2761 the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2762 FILE_ATTRIBUTE_NORMAL, NULL);
2764 if (the_file == INVALID_HANDLE_VALUE)
2766 ERR("Unable to create file %s\n",debugstr_w(source));
2767 rc = ERROR_FUNCTION_FAILED;
2771 WriteFile(the_file,data,size,&write,NULL);
2772 CloseHandle(the_file);
2773 TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
2775 HeapFree(GetProcessHeap(),0,data);
2780 /* Support functions for FDI functions */
2783 MSIPACKAGE* package;
2788 static void * cabinet_alloc(ULONG cb)
2790 return HeapAlloc(GetProcessHeap(), 0, cb);
2793 static void cabinet_free(void *pv)
2795 HeapFree(GetProcessHeap(), 0, pv);
2798 static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
2801 DWORD dwShareMode = 0;
2802 DWORD dwCreateDisposition = OPEN_EXISTING;
2803 switch (oflag & _O_ACCMODE)
2806 dwAccess = GENERIC_READ;
2807 dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
2810 dwAccess = GENERIC_WRITE;
2811 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2814 dwAccess = GENERIC_READ | GENERIC_WRITE;
2815 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2818 if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
2819 dwCreateDisposition = CREATE_NEW;
2820 else if (oflag & _O_CREAT)
2821 dwCreateDisposition = CREATE_ALWAYS;
2822 return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
2823 dwCreateDisposition, 0, NULL);
2826 static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
2829 if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
2834 static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
2837 if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
2842 static int cabinet_close(INT_PTR hf)
2844 return CloseHandle((HANDLE)hf) ? 0 : -1;
2847 static long cabinet_seek(INT_PTR hf, long dist, int seektype)
2849 /* flags are compatible and so are passed straight through */
2850 return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
2853 static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
2855 /* FIXME: try to do more processing in this function */
2858 case fdintCOPY_FILE:
2860 CabData *data = (CabData*) pfdin->pv;
2861 ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
2866 LPWSTR tracknametmp;
2867 static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
2869 if (data->file_name && lstrcmpiA(data->file_name,pfdin->psz1))
2872 file = cabinet_alloc((len+1)*sizeof(char));
2873 strcpy(file, data->cab_path);
2874 strcat(file, pfdin->psz1);
2876 TRACE("file: %s\n", debugstr_a(file));
2878 /* track this file so it can be deleted if not installed */
2879 trackpath=strdupAtoW(file);
2880 tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
2881 trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) +
2882 strlenW(tmpprefix)+1) * sizeof(WCHAR));
2884 strcpyW(trackname,tmpprefix);
2885 strcatW(trackname,tracknametmp);
2887 track_tempfile(data->package, trackname, trackpath);
2889 HeapFree(GetProcessHeap(),0,trackpath);
2890 HeapFree(GetProcessHeap(),0,trackname);
2891 HeapFree(GetProcessHeap(),0,tracknametmp);
2893 return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
2895 case fdintCLOSE_FILE_INFO:
2899 if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
2901 if (!LocalFileTimeToFileTime(&ft, &ftLocal))
2903 if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
2906 cabinet_close(pfdin->hf);
2914 /***********************************************************************
2915 * extract_cabinet_file
2917 * Extract files from a cab file.
2919 static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source,
2920 const WCHAR* path, const WCHAR* file)
2930 TRACE("Extracting %s (%s) to %s\n",debugstr_w(source),
2931 debugstr_w(file), debugstr_w(path));
2933 hfdi = FDICreate(cabinet_alloc,
2944 ERR("FDICreate failed\n");
2948 if (!(cabinet = strdupWtoA( source )))
2953 if (!(cab_path = strdupWtoA( path )))
2956 HeapFree(GetProcessHeap(), 0, cabinet);
2960 data.package = package;
2961 data.cab_path = cab_path;
2963 file_name = strdupWtoA(file);
2966 data.file_name = file_name;
2968 ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
2971 ERR("FDICopy failed\n");
2975 HeapFree(GetProcessHeap(), 0, cabinet);
2976 HeapFree(GetProcessHeap(), 0, cab_path);
2977 HeapFree(GetProcessHeap(), 0, file_name);
2982 static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path,
2987 MSIRECORD * row = 0;
2988 static WCHAR source[MAX_PATH];
2989 static const WCHAR ExecSeqQuery[] =
2990 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2991 'M','e','d','i','a',' ','W','H','E','R','E',' ',
2992 'L','a','s','t','S','e','q','u','e','n','c','e',' ','>','=',' ','%',
2993 'i',' ','O','R','D','E','R',' ','B','Y',' ',
2994 'L','a','s','t','S','e','q','u','e','n','c','e',0};
2999 static UINT last_sequence = 0;
3001 if (file->Attributes & msidbFileAttributesNoncompressed)
3003 TRACE("Uncompressed File, no media to ready.\n");
3004 return ERROR_SUCCESS;
3007 if (file->Sequence <= last_sequence)
3009 TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence);
3010 /*extract_a_cabinet_file(package, source,path,file->File); */
3011 return ERROR_SUCCESS;
3014 sprintfW(Query,ExecSeqQuery,file->Sequence);
3016 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3017 if (rc != ERROR_SUCCESS)
3020 rc = MSI_ViewExecute(view, 0);
3021 if (rc != ERROR_SUCCESS)
3023 MSI_ViewClose(view);
3024 msiobj_release(&view->hdr);
3028 rc = MSI_ViewFetch(view,&row);
3029 if (rc != ERROR_SUCCESS)
3031 MSI_ViewClose(view);
3032 msiobj_release(&view->hdr);
3035 seq = MSI_RecordGetInteger(row,2);
3036 last_sequence = seq;
3038 if (!MSI_RecordIsNull(row,4))
3041 MSI_RecordGetStringW(row,4,cab,&sz);
3042 TRACE("Source is CAB %s\n",debugstr_w(cab));
3043 /* the stream does not contain the # character */
3046 writeout_cabinet_stream(package,&cab[1],source);
3047 strcpyW(path,source);
3048 *(strrchrW(path,'\\')+1)=0;
3053 if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
3055 ERR("No Source dir defined \n");
3056 rc = ERROR_FUNCTION_FAILED;
3060 strcpyW(path,source);
3061 strcatW(source,cab);
3062 /* extract the cab file into a folder in the temp folder */
3064 if (MSI_GetPropertyW(package, cszTempFolder,path, &sz)
3066 GetTempPathW(MAX_PATH,path);
3069 rc = !extract_a_cabinet_file(package, source,path,NULL);
3074 MSI_GetPropertyW(package,cszSourceDir,source,&sz);
3075 strcpyW(path,source);
3077 msiobj_release(&row->hdr);
3078 MSI_ViewClose(view);
3079 msiobj_release(&view->hdr);
3083 inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
3085 UINT rc = ERROR_SUCCESS;
3087 LPWSTR install_path;
3089 install_path = resolve_folder(package, package->components[component].Directory,
3090 FALSE, FALSE, &folder);
3092 return ERROR_FUNCTION_FAILED;
3094 /* create the path */
3095 if (folder->State == 0)
3097 create_full_pathW(install_path);
3100 HeapFree(GetProcessHeap(), 0, install_path);
3105 static UINT ACTION_InstallFiles(MSIPACKAGE *package)
3107 UINT rc = ERROR_SUCCESS;
3110 WCHAR uipath[MAX_PATH];
3113 return ERROR_INVALID_HANDLE;
3115 /* increment progress bar each time action data is sent */
3116 ui_progress(package,1,1,0,0);
3118 for (index = 0; index < package->loaded_files; index++)
3120 WCHAR path_to_source[MAX_PATH];
3123 file = &package->files[index];
3125 if (file->Temporary)
3129 if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex,
3130 INSTALLSTATE_LOCAL))
3132 ui_progress(package,2,file->FileSize,0,0);
3133 TRACE("File %s is not scheduled for install\n",
3134 debugstr_w(file->File));
3139 if ((file->State == 1) || (file->State == 2))
3142 MSICOMPONENT* comp = NULL;
3144 TRACE("Installing %s\n",debugstr_w(file->File));
3145 rc = ready_media_for_file(package, path_to_source, file);
3148 * our file table could change here because a new temp file
3149 * may have been created
3151 file = &package->files[index];
3152 if (rc != ERROR_SUCCESS)
3154 ERR("Unable to ready media\n");
3155 rc = ERROR_FUNCTION_FAILED;
3159 create_component_directory( package, file->ComponentIndex);
3161 /* recalculate file paths because things may have changed */
3163 if (file->ComponentIndex >= 0)
3164 comp = &package->components[file->ComponentIndex];
3166 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
3167 HeapFree(GetProcessHeap(),0,file->TargetPath);
3169 file->TargetPath = build_directory_name(2, p, file->FileName);
3170 HeapFree(GetProcessHeap(),0,p);
3172 if (file->Attributes & msidbFileAttributesNoncompressed)
3174 p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
3175 file->SourcePath = build_directory_name(2, p, file->ShortName);
3176 HeapFree(GetProcessHeap(),0,p);
3179 file->SourcePath = build_directory_name(2, path_to_source,
3183 TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
3184 debugstr_w(file->TargetPath));
3187 uirow=MSI_CreateRecord(9);
3188 MSI_RecordSetStringW(uirow,1,file->File);
3189 strcpyW(uipath,file->TargetPath);
3190 *(strrchrW(uipath,'\\')+1)=0;
3191 MSI_RecordSetStringW(uirow,9,uipath);
3192 MSI_RecordSetInteger(uirow,6,file->FileSize);
3193 ui_actiondata(package,szInstallFiles,uirow);
3194 msiobj_release( &uirow->hdr );
3195 ui_progress(package,2,file->FileSize,0,0);
3198 if (file->Attributes & msidbFileAttributesNoncompressed)
3199 rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
3201 rc = MoveFileW(file->SourcePath, file->TargetPath);
3205 rc = GetLastError();
3206 ERR("Unable to move/copy file (%s -> %s) (error %d)\n",
3207 debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
3209 if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
3211 if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE))
3212 ERR("Unable to copy file (%s -> %s) (error %ld)\n",
3213 debugstr_w(file->SourcePath),
3214 debugstr_w(file->TargetPath), GetLastError());
3215 if (!(file->Attributes & msidbFileAttributesNoncompressed))
3216 DeleteFileW(file->SourcePath);
3219 else if (rc == ERROR_FILE_NOT_FOUND)
3221 ERR("Source File Not Found! Continuing\n");
3224 else if (file->Attributes & msidbFileAttributesVital)
3226 ERR("Ignoring Error and continuing (nonvital file)...\n");
3241 inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
3242 LPWSTR* file_source)
3247 return ERROR_INVALID_HANDLE;
3249 for (index = 0; index < package->loaded_files; index ++)
3251 if (strcmpW(file_key,package->files[index].File)==0)
3253 if (package->files[index].State >= 2)
3255 *file_source = strdupW(package->files[index].TargetPath);
3256 return ERROR_SUCCESS;
3259 return ERROR_FILE_NOT_FOUND;
3263 return ERROR_FUNCTION_FAILED;
3266 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
3270 MSIRECORD * row = 0;
3271 static const WCHAR ExecSeqQuery[] =
3272 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3273 'D','u','p','l','i','c','a','t','e','F','i','l','e',0};
3276 return ERROR_INVALID_HANDLE;
3278 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3279 if (rc != ERROR_SUCCESS)
3280 return ERROR_SUCCESS;
3282 rc = MSI_ViewExecute(view, 0);
3283 if (rc != ERROR_SUCCESS)
3285 MSI_ViewClose(view);
3286 msiobj_release(&view->hdr);
3292 WCHAR file_key[0x100];
3293 WCHAR *file_source = NULL;
3294 WCHAR dest_name[0x100];
3295 LPWSTR dest_path, dest;
3296 WCHAR component[0x100];
3297 INT component_index;
3301 rc = MSI_ViewFetch(view,&row);
3302 if (rc != ERROR_SUCCESS)
3309 rc = MSI_RecordGetStringW(row,2,component,&sz);
3310 if (rc != ERROR_SUCCESS)
3312 ERR("Unable to get component\n");
3313 msiobj_release(&row->hdr);
3317 component_index = get_loaded_component(package,component);
3319 if (!ACTION_VerifyComponentForAction(package, component_index,
3320 INSTALLSTATE_LOCAL))
3322 TRACE("Skipping copy due to disabled component\n");
3324 /* the action taken was the same as the current install state */
3325 package->components[component_index].Action =
3326 package->components[component_index].Installed;
3328 msiobj_release(&row->hdr);
3332 package->components[component_index].Action = INSTALLSTATE_LOCAL;
3335 rc = MSI_RecordGetStringW(row,3,file_key,&sz);
3336 if (rc != ERROR_SUCCESS)
3338 ERR("Unable to get file key\n");
3339 msiobj_release(&row->hdr);
3343 rc = get_file_target(package,file_key,&file_source);
3345 if (rc != ERROR_SUCCESS)
3347 ERR("Original file unknown %s\n",debugstr_w(file_key));
3348 msiobj_release(&row->hdr);
3349 HeapFree(GetProcessHeap(),0,file_source);
3353 if (MSI_RecordIsNull(row,4))
3355 strcpyW(dest_name,strrchrW(file_source,'\\')+1);
3360 MSI_RecordGetStringW(row,4,dest_name,&sz);
3361 reduce_to_longfilename(dest_name);
3364 if (MSI_RecordIsNull(row,5))
3367 dest_path = strdupW(file_source);
3368 p = strrchrW(dest_path,'\\');
3374 WCHAR destkey[0x100];
3376 MSI_RecordGetStringW(row,5,destkey,&sz);
3378 dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
3381 ERR("Unable to get destination folder\n");
3382 msiobj_release(&row->hdr);
3383 HeapFree(GetProcessHeap(),0,file_source);
3388 dest = build_directory_name(2, dest_path, dest_name);
3390 TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
3393 if (strcmpW(file_source,dest))
3394 rc = !CopyFileW(file_source,dest,TRUE);
3398 if (rc != ERROR_SUCCESS)
3399 ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError());
3401 FIXME("We should track these duplicate files as well\n");
3403 msiobj_release(&row->hdr);
3404 HeapFree(GetProcessHeap(),0,dest_path);
3405 HeapFree(GetProcessHeap(),0,dest);
3406 HeapFree(GetProcessHeap(),0,file_source);
3408 MSI_ViewClose(view);
3409 msiobj_release(&view->hdr);
3414 /* OK this value is "interpreted" and then formatted based on the
3415 first few characters */
3416 static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type,
3420 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
3426 LPWSTR deformated = NULL;
3429 deformat_string(package, &value[2], &deformated);
3431 /* binary value type */
3435 *size = (strlenW(ptr)/2)+1;
3437 *size = strlenW(ptr)/2;
3439 data = HeapAlloc(GetProcessHeap(),0,*size);
3445 /* if uneven pad with a zero in front */
3451 data[count] = (BYTE)strtol(byte,NULL,0);
3453 TRACE("Uneven byte count\n");
3461 data[count] = (BYTE)strtol(byte,NULL,0);
3464 HeapFree(GetProcessHeap(),0,deformated);
3466 TRACE("Data %li bytes(%i)\n",*size,count);
3473 deformat_string(package, &value[1], &deformated);
3476 *size = sizeof(DWORD);
3477 data = HeapAlloc(GetProcessHeap(),0,*size);
3483 if ( (*p < '0') || (*p > '9') )
3489 if (deformated[0] == '-')
3492 TRACE("DWORD %li\n",*(LPDWORD)data);
3494 HeapFree(GetProcessHeap(),0,deformated);
3499 static const WCHAR szMulti[] = {'[','~',']',0};
3508 *type=REG_EXPAND_SZ;
3516 if (strstrW(value,szMulti))
3517 *type = REG_MULTI_SZ;
3519 *size = deformat_string(package, ptr,(LPWSTR*)&data);
3524 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
3528 MSIRECORD * row = 0;
3529 static const WCHAR ExecSeqQuery[] =
3530 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3531 'R','e','g','i','s','t','r','y',0 };
3534 return ERROR_INVALID_HANDLE;
3536 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3537 if (rc != ERROR_SUCCESS)
3538 return ERROR_SUCCESS;
3540 rc = MSI_ViewExecute(view, 0);
3541 if (rc != ERROR_SUCCESS)
3543 MSI_ViewClose(view);
3544 msiobj_release(&view->hdr);
3548 /* increment progress bar each time action data is sent */
3549 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
3553 static const WCHAR szHCR[] =
3554 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
3555 'R','O','O','T','\\',0};
3556 static const WCHAR szHCU[] =
3557 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
3558 'U','S','E','R','\\',0};
3559 static const WCHAR szHLM[] =
3560 {'H','K','E','Y','_','L','O','C','A','L','_',
3561 'M','A','C','H','I','N','E','\\',0};
3562 static const WCHAR szHU[] =
3563 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
3565 LPSTR value_data = NULL;
3566 HKEY root_key, hkey;
3568 LPWSTR value, key, name, component, deformated;
3570 INT component_index;
3575 rc = MSI_ViewFetch(view,&row);
3576 if (rc != ERROR_SUCCESS)
3581 ui_progress(package,2,0,0,0);
3588 component = load_dynamic_stringW(row, 6);
3589 component_index = get_loaded_component(package,component);
3591 if (!ACTION_VerifyComponentForAction(package, component_index,
3592 INSTALLSTATE_LOCAL))
3594 TRACE("Skipping write due to disabled component\n");
3595 msiobj_release(&row->hdr);
3597 package->components[component_index].Action =
3598 package->components[component_index].Installed;
3603 package->components[component_index].Action = INSTALLSTATE_LOCAL;
3605 name = load_dynamic_stringW(row, 4);
3606 if( MSI_RecordIsNull(row,5) && name )
3608 /* null values can have special meanings */
3609 if (name[0]=='-' && name[1] == 0)
3611 msiobj_release(&row->hdr);
3614 else if ((name[0]=='+' && name[1] == 0) ||
3615 (name[0] == '*' && name[1] == 0))
3617 HeapFree(GetProcessHeap(),0,name);
3622 root = MSI_RecordGetInteger(row,2);
3623 key = load_dynamic_stringW(row, 3);
3626 /* get the root key */
3629 case 0: root_key = HKEY_CLASSES_ROOT;
3632 case 1: root_key = HKEY_CURRENT_USER;
3635 case 2: root_key = HKEY_LOCAL_MACHINE;
3638 case 3: root_key = HKEY_USERS;
3642 ERR("Unknown root %i\n",root);
3649 msiobj_release(&row->hdr);
3653 deformat_string(package, key , &deformated);
3654 size = strlenW(deformated) + strlenW(szRoot) + 1;
3655 uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
3656 strcpyW(uikey,szRoot);
3657 strcatW(uikey,deformated);
3659 if (RegCreateKeyW( root_key, deformated, &hkey))
3661 ERR("Could not create key %s\n",debugstr_w(deformated));
3662 msiobj_release(&row->hdr);
3663 HeapFree(GetProcessHeap(),0,deformated);
3666 HeapFree(GetProcessHeap(),0,deformated);
3668 value = load_dynamic_stringW(row,5);
3670 value_data = parse_value(package, value, &type, &size);
3673 static const WCHAR szEmpty[] = {0};
3674 value_data = (LPSTR)strdupW(szEmpty);
3679 deformat_string(package, name, &deformated);
3681 TRACE("Setting value %s\n",debugstr_w(deformated));
3682 RegSetValueExW(hkey, deformated, 0, type, value_data, size);
3684 uirow = MSI_CreateRecord(3);
3685 MSI_RecordSetStringW(uirow,2,deformated);
3686 MSI_RecordSetStringW(uirow,1,uikey);
3689 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
3691 MSI_RecordSetStringW(uirow,3,value);
3693 ui_actiondata(package,szWriteRegistryValues,uirow);
3694 msiobj_release( &uirow->hdr );
3696 HeapFree(GetProcessHeap(),0,value_data);
3697 HeapFree(GetProcessHeap(),0,value);
3698 HeapFree(GetProcessHeap(),0,deformated);
3700 msiobj_release(&row->hdr);
3703 HeapFree(GetProcessHeap(),0,uikey);
3704 HeapFree(GetProcessHeap(),0,key);
3705 HeapFree(GetProcessHeap(),0,name);
3706 HeapFree(GetProcessHeap(),0,component);
3708 MSI_ViewClose(view);
3709 msiobj_release(&view->hdr);
3713 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3715 return ERROR_SUCCESS;
3719 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3723 static const WCHAR q1[]=
3724 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3725 'R','e','g','i','s','t','r','y',0};
3728 MSIRECORD * row = 0;
3731 TRACE(" InstallValidate \n");
3733 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3734 if (rc != ERROR_SUCCESS)
3735 return ERROR_SUCCESS;
3737 rc = MSI_ViewExecute(view, 0);
3738 if (rc != ERROR_SUCCESS)
3740 MSI_ViewClose(view);
3741 msiobj_release(&view->hdr);
3746 rc = MSI_ViewFetch(view,&row);
3747 if (rc != ERROR_SUCCESS)
3754 msiobj_release(&row->hdr);
3756 MSI_ViewClose(view);
3757 msiobj_release(&view->hdr);
3759 total = total + progress * REG_PROGRESS_VALUE;
3760 total = total + package->loaded_components * COMPONENT_PROGRESS_VALUE;
3761 for (i=0; i < package->loaded_files; i++)
3762 total += package->files[i].FileSize;
3763 ui_progress(package,0,total,0,0);
3765 for(i = 0; i < package->loaded_features; i++)
3767 MSIFEATURE* feature = &package->features[i];
3768 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
3769 debugstr_w(feature->Feature), feature->Installed, feature->Action,
3770 feature->ActionRequest);
3773 return ERROR_SUCCESS;
3776 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3779 MSIQUERY * view = NULL;
3780 MSIRECORD * row = 0;
3781 static const WCHAR ExecSeqQuery[] =
3782 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3783 'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n',0};
3784 static const WCHAR title[]=
3785 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3787 TRACE("Checking launch conditions\n");
3789 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3790 if (rc != ERROR_SUCCESS)
3791 return ERROR_SUCCESS;
3793 rc = MSI_ViewExecute(view, 0);
3794 if (rc != ERROR_SUCCESS)
3796 MSI_ViewClose(view);
3797 msiobj_release(&view->hdr);
3802 while (rc == ERROR_SUCCESS)
3805 LPWSTR message = NULL;
3807 rc = MSI_ViewFetch(view,&row);
3808 if (rc != ERROR_SUCCESS)
3814 cond = load_dynamic_stringW(row,1);
3816 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
3819 message = load_dynamic_stringW(row,2);
3820 deformat_string(package,message,&deformated);
3821 MessageBoxW(NULL,deformated,title,MB_OK);
3822 HeapFree(GetProcessHeap(),0,message);
3823 HeapFree(GetProcessHeap(),0,deformated);
3824 rc = ERROR_FUNCTION_FAILED;
3826 HeapFree(GetProcessHeap(),0,cond);
3827 msiobj_release(&row->hdr);
3829 MSI_ViewClose(view);
3830 msiobj_release(&view->hdr);
3834 static LPWSTR resolve_keypath( MSIPACKAGE* package, INT
3837 MSICOMPONENT* cmp = &package->components[component_index];
3839 if (cmp->KeyPath[0]==0)
3841 LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
3844 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3847 MSIRECORD * row = 0;
3849 LPWSTR key,deformated,buffer,name,deformated_name;
3850 static const WCHAR ExecSeqQuery[] =
3851 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3852 'R','e','g','i','s','t','r','y',' ','W','H','E','R','E',' ',
3853 'R','e','g','i','s','t','r','y',' ','=',' ' ,'`','%','s','`',0 };
3854 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3855 static const WCHAR fmt2[]=
3856 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3858 rc = MSI_OpenQuery(package->db,&view,ExecSeqQuery,cmp->KeyPath);
3860 if (rc!=ERROR_SUCCESS)
3863 rc = MSI_ViewExecute(view, 0);
3864 if (rc != ERROR_SUCCESS)
3866 MSI_ViewClose(view);
3867 msiobj_release(&view->hdr);
3871 rc = MSI_ViewFetch(view,&row);
3872 if (rc != ERROR_SUCCESS)
3874 MSI_ViewClose(view);
3875 msiobj_release(&view->hdr);
3879 root = MSI_RecordGetInteger(row,2);
3880 key = load_dynamic_stringW(row, 3);
3881 name = load_dynamic_stringW(row, 4);
3882 deformat_string(package, key , &deformated);
3883 deformat_string(package, name, &deformated_name);
3885 len = strlenW(deformated) + 6;
3886 if (deformated_name)
3887 len+=strlenW(deformated_name);
3889 buffer = HeapAlloc(GetProcessHeap(),0, len *sizeof(WCHAR));
3891 if (deformated_name)
3892 sprintfW(buffer,fmt2,root,deformated,deformated_name);
3894 sprintfW(buffer,fmt,root,deformated);
3896 HeapFree(GetProcessHeap(),0,key);
3897 HeapFree(GetProcessHeap(),0,deformated);
3898 HeapFree(GetProcessHeap(),0,name);
3899 HeapFree(GetProcessHeap(),0,deformated_name);
3900 msiobj_release(&row->hdr);
3901 MSI_ViewClose(view);
3902 msiobj_release(&view->hdr);
3906 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3908 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3914 j = get_loaded_file(package,cmp->KeyPath);
3918 LPWSTR p = strdupW(package->files[j].TargetPath);
3925 static HKEY openSharedDLLsKey()
3928 static const WCHAR path[] =
3929 {'S','o','f','t','w','a','r','e','\\',
3930 'M','i','c','r','o','s','o','f','t','\\',
3931 'W','i','n','d','o','w','s','\\',
3932 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3933 'S','h','a','r','e','d','D','L','L','s',0};
3935 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3939 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3944 DWORD sz = sizeof(count);
3947 hkey = openSharedDLLsKey();
3948 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3949 if (rc != ERROR_SUCCESS)
3955 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
3959 hkey = openSharedDLLsKey();
3961 RegSetValueExW(hkey,path,0,REG_DWORD,
3962 (LPBYTE)&count,sizeof(count));
3964 RegDeleteValueW(hkey,path);
3970 * Return TRUE if the count should be written out and FALSE if not
3972 static void ACTION_RefCountComponent( MSIPACKAGE* package, UINT index)
3978 /* only refcount DLLs */
3979 if (package->components[index].KeyPath[0]==0 ||
3980 package->components[index].Attributes &
3981 msidbComponentAttributesRegistryKeyPath ||
3982 package->components[index].Attributes &
3983 msidbComponentAttributesODBCDataSource)
3987 count = ACTION_GetSharedDLLsCount(package->components[index].
3989 write = (count > 0);
3991 if (package->components[index].Attributes &
3992 msidbComponentAttributesSharedDllRefCount)
3996 /* increment counts */
3997 for (j = 0; j < package->loaded_features; j++)
4001 if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_LOCAL))
4004 for (i = 0; i < package->features[j].ComponentCount; i++)
4006 if (package->features[j].Components[i] == index)
4010 /* decrement counts */
4011 for (j = 0; j < package->loaded_features; j++)
4014 if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_ABSENT))
4017 for (i = 0; i < package->features[j].ComponentCount; i++)
4019 if (package->features[j].Components[i] == index)
4024 /* ref count all the files in the component */
4026 for (j = 0; j < package->loaded_files; j++)
4028 if (package->files[j].Temporary)
4030 if (package->files[j].ComponentIndex == index)
4031 ACTION_WriteSharedDLLsCount(package->files[j].TargetPath,count);
4034 /* add a count for permenent */
4035 if (package->components[index].Attributes &
4036 msidbComponentAttributesPermanent)
4039 package->components[index].RefCount = count;
4042 ACTION_WriteSharedDLLsCount(package->components[index].FullKeypath,
4043 package->components[index].RefCount);
4047 * Ok further analysis makes me think that this work is
4048 * actually done in the PublishComponents and PublishFeatures
4049 * step, and not here. It appears like the keypath and all that is
4050 * resolved in this step, however actually written in the Publish steps.
4051 * But we will leave it here for now because it is unclear
4053 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
4056 WCHAR squished_pc[GUID_SIZE];
4057 WCHAR squished_cc[GUID_SIZE];
4060 HKEY hkey=0,hkey2=0;
4063 return ERROR_INVALID_HANDLE;
4065 /* writes the Component and Features values to the registry */
4066 productcode = load_dynamic_property(package,szProductCode,&rc);
4070 rc = MSIREG_OpenComponents(&hkey);
4071 if (rc != ERROR_SUCCESS)
4074 squash_guid(productcode,squished_pc);
4075 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
4076 for (i = 0; i < package->loaded_components; i++)
4078 ui_progress(package,2,0,0,0);
4079 if (package->components[i].ComponentId[0]!=0)
4081 WCHAR *keypath = NULL;
4084 squash_guid(package->components[i].ComponentId,squished_cc);
4086 keypath = resolve_keypath(package,i);
4087 package->components[i].FullKeypath = keypath;
4089 /* do the refcounting */
4090 ACTION_RefCountComponent( package, i);
4092 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
4093 debugstr_w(package->components[i].Component),
4094 debugstr_w(squished_cc),
4095 debugstr_w(package->components[i].FullKeypath),
4096 package->components[i].RefCount);
4098 * Write the keypath out if the component is to be registered
4099 * and delete the key if the component is to be deregistered
4101 if (ACTION_VerifyComponentForAction(package, i,
4102 INSTALLSTATE_LOCAL))
4104 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
4105 if (rc != ERROR_SUCCESS)
4110 RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath,
4111 (strlenW(keypath)+1)*sizeof(WCHAR));
4113 if (package->components[i].Attributes &
4114 msidbComponentAttributesPermanent)
4116 static const WCHAR szPermKey[] =
4117 { '0','0','0','0','0','0','0','0','0','0','0','0',
4118 '0','0','0','0','0','0','0', '0','0','0','0','0',
4119 '0','0','0','0','0','0','0','0',0};
4121 RegSetValueExW(hkey2,szPermKey,0,REG_SZ,
4123 (strlenW(keypath)+1)*sizeof(WCHAR));
4129 uirow = MSI_CreateRecord(3);
4130 MSI_RecordSetStringW(uirow,1,productcode);
4131 MSI_RecordSetStringW(uirow,2,package->components[i].
4133 MSI_RecordSetStringW(uirow,3,keypath);
4134 ui_actiondata(package,szProcessComponents,uirow);
4135 msiobj_release( &uirow->hdr );
4138 else if (ACTION_VerifyComponentForAction(package, i,
4139 INSTALLSTATE_ABSENT))
4143 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
4144 if (rc != ERROR_SUCCESS)
4147 RegDeleteValueW(hkey2,squished_pc);
4149 /* if the key is empty delete it */
4150 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
4152 if (res == ERROR_NO_MORE_ITEMS)
4153 RegDeleteKeyW(hkey,squished_cc);
4156 uirow = MSI_CreateRecord(2);
4157 MSI_RecordSetStringW(uirow,1,productcode);
4158 MSI_RecordSetStringW(uirow,2,package->components[i].
4160 ui_actiondata(package,szProcessComponents,uirow);
4161 msiobj_release( &uirow->hdr );
4166 HeapFree(GetProcessHeap(), 0, productcode);
4179 BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
4180 LPWSTR lpszName, LONG_PTR lParam)
4183 typelib_struct *tl_struct = (typelib_struct*) lParam;
4184 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
4188 if (!IS_INTRESOURCE(lpszName))
4190 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
4194 sz = strlenW(tl_struct->source)+4;
4195 sz *= sizeof(WCHAR);
4197 tl_struct->path = HeapAlloc(GetProcessHeap(),0,sz);
4198 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
4200 TRACE("trying %s\n", debugstr_w(tl_struct->path));
4201 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
4202 if (!SUCCEEDED(res))
4204 HeapFree(GetProcessHeap(),0,tl_struct->path);
4205 tl_struct->path = NULL;
4210 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
4211 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
4213 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
4217 HeapFree(GetProcessHeap(),0,tl_struct->path);
4218 tl_struct->path = NULL;
4220 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
4221 ITypeLib_Release(tl_struct->ptLib);
4226 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
4229 * OK this is a bit confusing.. I am given a _Component key and I believe
4230 * that the file that is being registered as a type library is the "key file
4231 * of that component" which I interpret to mean "The file in the KeyPath of
4236 MSIRECORD * row = 0;
4237 static const WCHAR Query[] =
4238 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4239 'T','y','p','e','L','i','b',0};
4242 return ERROR_INVALID_HANDLE;
4244 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4245 if (rc != ERROR_SUCCESS)
4246 return ERROR_SUCCESS;
4248 rc = MSI_ViewExecute(view, 0);
4249 if (rc != ERROR_SUCCESS)
4251 MSI_ViewClose(view);
4252 msiobj_release(&view->hdr);
4258 WCHAR component[0x100];
4262 typelib_struct tl_struct;
4264 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
4266 rc = MSI_ViewFetch(view,&row);
4267 if (rc != ERROR_SUCCESS)
4274 MSI_RecordGetStringW(row,3,component,&sz);
4276 index = get_loaded_component(package,component);
4279 msiobj_release(&row->hdr);
4283 if (!ACTION_VerifyComponentForAction(package, index,
4284 INSTALLSTATE_LOCAL))
4286 TRACE("Skipping typelib reg due to disabled component\n");
4287 msiobj_release(&row->hdr);
4289 package->components[index].Action =
4290 package->components[index].Installed;
4295 package->components[index].Action = INSTALLSTATE_LOCAL;
4297 index = get_loaded_file(package,package->components[index].KeyPath);
4301 msiobj_release(&row->hdr);
4305 guid = load_dynamic_stringW(row,1);
4306 module = LoadLibraryExW(package->files[index].TargetPath, NULL,
4307 LOAD_LIBRARY_AS_DATAFILE);
4310 CLSIDFromString(guid, &tl_struct.clsid);
4311 tl_struct.source = strdupW(package->files[index].TargetPath);
4312 tl_struct.path = NULL;
4314 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
4315 (LONG_PTR)&tl_struct);
4317 if (tl_struct.path != NULL)
4320 WCHAR helpid[0x100];
4324 MSI_RecordGetStringW(row,6,helpid,&sz);
4326 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
4327 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
4328 HeapFree(GetProcessHeap(),0,help);
4330 if (!SUCCEEDED(res))
4331 ERR("Failed to register type library %s\n",
4332 debugstr_w(tl_struct.path));
4335 ui_actiondata(package,szRegisterTypeLibraries,row);
4337 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
4340 ITypeLib_Release(tl_struct.ptLib);
4341 HeapFree(GetProcessHeap(),0,tl_struct.path);
4344 ERR("Failed to load type library %s\n",
4345 debugstr_w(tl_struct.source));
4347 FreeLibrary(module);
4348 HeapFree(GetProcessHeap(),0,tl_struct.source);
4351 ERR("Could not load file! %s\n",
4352 debugstr_w(package->files[index].TargetPath));
4353 msiobj_release(&row->hdr);
4355 MSI_ViewClose(view);
4356 msiobj_release(&view->hdr);
4360 static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
4362 static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
4365 MSIRECORD * row = 0;
4366 static const WCHAR ExecSeqQuery[] =
4367 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4368 'A','p','p','I' ,'d',' ','w','h','e','r','e',' ',
4369 'A','p','p','I','d','=','`','%','s','`',0};
4374 return ERROR_INVALID_HANDLE;
4376 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, clsid);
4377 if (rc != ERROR_SUCCESS)
4380 rc = MSI_ViewExecute(view, 0);
4381 if (rc != ERROR_SUCCESS)
4383 MSI_ViewClose(view);
4384 msiobj_release(&view->hdr);
4388 RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
4389 RegCreateKeyW(hkey2,clsid,&hkey3);
4390 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
4391 (strlenW(app)+1)*sizeof(WCHAR));
4393 rc = MSI_ViewFetch(view,&row);
4394 if (rc != ERROR_SUCCESS)
4396 MSI_ViewClose(view);
4397 msiobj_release(&view->hdr);
4401 if (!MSI_RecordIsNull(row,2))
4403 LPWSTR deformated=0;
4405 static const WCHAR szRemoteServerName[] =
4406 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',
4408 buffer = load_dynamic_stringW(row,2);
4409 size = deformat_string(package,buffer,&deformated);
4410 RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated,
4412 HeapFree(GetProcessHeap(),0,deformated);
4413 HeapFree(GetProcessHeap(),0,buffer);
4416 if (!MSI_RecordIsNull(row,3))
4418 static const WCHAR szLocalService[] =
4419 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
4421 buffer = load_dynamic_stringW(row,3);
4422 size = (strlenW(buffer)+1) * sizeof(WCHAR);
4423 RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size);
4424 HeapFree(GetProcessHeap(),0,buffer);
4427 if (!MSI_RecordIsNull(row,4))
4429 static const WCHAR szService[] =
4430 {'S','e','r','v','i','c','e',
4431 'P','a','r','a','m','e','t','e','r','s',0};
4433 buffer = load_dynamic_stringW(row,4);
4434 size = (strlenW(buffer)+1) * sizeof(WCHAR);
4435 RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size);
4436 HeapFree(GetProcessHeap(),0,buffer);
4439 if (!MSI_RecordIsNull(row,5))
4441 static const WCHAR szDLL[] =
4442 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
4444 buffer = load_dynamic_stringW(row,5);
4445 size = (strlenW(buffer)+1) * sizeof(WCHAR);
4446 RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size);
4447 HeapFree(GetProcessHeap(),0,buffer);
4450 if (!MSI_RecordIsNull(row,6))
4452 static const WCHAR szActivate[] =
4453 {'A','c','t','i','v','a','t','e','A','s',
4454 'S','t','o','r','a','g','e',0};
4455 static const WCHAR szY[] = {'Y',0};
4457 if (MSI_RecordGetInteger(row,6))
4458 RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
4461 if (!MSI_RecordIsNull(row,7))
4463 static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
4464 static const WCHAR szUser[] =
4465 {'I','n','t','e','r','a','c','t','i','v','e',' ',
4468 if (MSI_RecordGetInteger(row,7))
4469 RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34);
4472 msiobj_release(&row->hdr);
4473 MSI_ViewClose(view);
4474 msiobj_release(&view->hdr);
4480 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
4483 * Again I am assuming the words, "Whose key file represents" when referring
4484 * to a Component as to meaning that Components KeyPath file
4486 * Also there is a very strong connection between ClassInfo and ProgID
4487 * that I am mostly glossing over.
4488 * What would be more propper is to load the ClassInfo and the ProgID info
4489 * into memory data structures and then be able to enable and disable them
4490 * based on component.
4495 MSIRECORD * row = 0;
4496 static const WCHAR ExecSeqQuery[] =
4497 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4498 'C','l','a','s','s',0};
4499 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
4500 static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
4501 static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
4502 static const WCHAR szSpace[] = {' ',0};
4503 HKEY hkey,hkey2,hkey3;
4504 LPWSTR argument,deformated;
4507 return ERROR_INVALID_HANDLE;
4509 rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
4510 if (rc != ERROR_SUCCESS)
4511 return ERROR_FUNCTION_FAILED;
4513 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4514 if (rc != ERROR_SUCCESS)
4520 rc = MSI_ViewExecute(view, 0);
4521 if (rc != ERROR_SUCCESS)
4523 MSI_ViewClose(view);
4524 msiobj_release(&view->hdr);
4531 WCHAR buffer[0x100];
4537 rc = MSI_ViewFetch(view,&row);
4538 if (rc != ERROR_SUCCESS)
4545 MSI_RecordGetStringW(row,3,buffer,&sz);
4547 index = get_loaded_component(package,buffer);
4551 msiobj_release(&row->hdr);
4555 if (!ACTION_VerifyComponentForAction(package, index,
4556 INSTALLSTATE_LOCAL))
4558 TRACE("Skipping class reg due to disabled component\n");
4559 msiobj_release(&row->hdr);
4561 package->components[index].Action =
4562 package->components[index].Installed;
4567 package->components[index].Action = INSTALLSTATE_LOCAL;
4570 MSI_RecordGetStringW(row,1,clsid,&sz);
4571 RegCreateKeyW(hkey,clsid,&hkey2);
4573 if (!MSI_RecordIsNull(row,5))
4576 MSI_RecordGetStringW(row,5,desc,&sz);
4578 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc,
4579 (strlenW(desc)+1)*sizeof(WCHAR));
4585 MSI_RecordGetStringW(row,2,buffer,&sz);
4587 RegCreateKeyW(hkey2,buffer,&hkey3);
4589 index = get_loaded_file(package,package->components[index].KeyPath);
4591 argument = load_dynamic_stringW(row,11);
4592 size = deformat_string(package,argument,&deformated);
4594 size+=sizeof(WCHAR);
4595 HeapFree(GetProcessHeap(),0,argument);
4596 size += (strlenW(package->files[index].TargetPath))*sizeof(WCHAR);
4598 argument = HeapAlloc(GetProcessHeap(),0,size+sizeof(WCHAR));
4599 strcpyW(argument,package->files[index].TargetPath);
4602 strcatW(argument,szSpace);
4603 strcatW(argument,deformated);
4606 RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
4607 HeapFree(GetProcessHeap(),0,deformated);
4608 HeapFree(GetProcessHeap(),0,argument);
4612 if (!MSI_RecordIsNull(row,4))
4615 MSI_RecordGetStringW(row,4,buffer,&sz);
4617 RegCreateKeyW(hkey2,szProgID,&hkey3);
4619 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer,
4620 (strlenW(buffer)+1)*sizeof(WCHAR));
4625 if (!MSI_RecordIsNull(row,6))
4628 MSI_RecordGetStringW(row,6,buffer,&sz);
4630 RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer,
4631 (strlenW(buffer)+1)*sizeof(WCHAR));
4633 register_appid(package,buffer,desc);
4637 if (!MSI_RecordIsNull(row,7))
4639 FIXME("Process field 7\n");
4642 if (!MSI_RecordIsNull(row,8))
4644 static const WCHAR szDefaultIcon[] =
4645 {'D','e','f','a','u','l','t','I','c','o','n',0};
4647 LPWSTR FileName = load_dynamic_stringW(row,8);
4651 RegCreateKeyW(hkey2,szDefaultIcon,&hkey3);
4652 build_icon_path(package,FileName,&FilePath);
4653 if (!MSI_RecordIsNull(row,9))
4655 static const WCHAR index_fmt[] = {',','%','i',0};
4656 WCHAR index_buf[20];
4657 index = MSI_RecordGetInteger(row,9);
4658 sprintfW(index_buf,index_fmt,index);
4659 size = strlenW(FilePath)+strlenW(index_buf)+1;
4660 size *= sizeof(WCHAR);
4661 HeapReAlloc(GetProcessHeap(),0,FilePath,size);
4663 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)FilePath,
4664 (strlenW(FilePath)+1) * sizeof(WCHAR));
4665 HeapFree(GetProcessHeap(),0,FilePath);
4666 HeapFree(GetProcessHeap(),0,FileName);
4670 if (!MSI_RecordIsNull(row,10))
4672 static const WCHAR szInproc32[] =
4673 {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',
4675 static const WCHAR szInproc[] =
4676 {'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
4677 INT i = MSI_RecordGetInteger(row,10);
4678 if (i != MSI_NULL_INTEGER && i > 0 && i < 4)
4680 static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0};
4681 static const WCHAR ole32[] =
4682 {'o','l','e','3','2','.','d','l','l',0};
4686 size = strlenW(ole2) * sizeof(WCHAR);
4687 RegCreateKeyW(hkey2,szInproc,&hkey3);
4688 RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole2, size);
4692 size = strlenW(ole32) * sizeof(WCHAR);
4693 RegCreateKeyW(hkey2,szInproc32,&hkey3);
4694 RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole32,size);
4698 size = strlenW(ole2) * sizeof(WCHAR);
4699 RegCreateKeyW(hkey2,szInproc,&hkey3);
4700 RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole2, size);
4702 size = strlenW(ole32) * sizeof(WCHAR);
4703 RegCreateKeyW(hkey2,szInproc32,&hkey3);
4704 RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole32,size);
4712 RegCreateKeyW(hkey2,szInproc32,&hkey3);
4713 argument = load_dynamic_stringW(row,10);
4714 reduce_to_longfilename(argument);
4715 size = strlenW(argument)*sizeof(WCHAR);
4717 RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
4718 HeapFree(GetProcessHeap(),0,argument);
4726 ui_actiondata(package,szRegisterClassInfo,row);
4728 msiobj_release(&row->hdr);
4730 MSI_ViewClose(view);
4731 msiobj_release(&view->hdr);
4738 static UINT register_progid_base(MSIPACKAGE* package, MSIRECORD * row,
4741 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
4742 static const WCHAR szDefaultIcon[] =
4743 {'D','e','f','a','u','l','t','I','c','o','n',0};
4745 WCHAR buffer[0x100];
4750 MSI_RecordGetStringW(row,1,buffer,&sz);
4751 RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
4753 if (!MSI_RecordIsNull(row,4))
4756 MSI_RecordGetStringW(row,4,buffer,&sz);
4757 RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
4761 if (!MSI_RecordIsNull(row,3))
4765 MSI_RecordGetStringW(row,3,buffer,&sz);
4766 RegCreateKeyW(hkey,szCLSID,&hkey2);
4767 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
4771 strcpyW(clsid,buffer);
4777 FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
4778 return ERROR_FUNCTION_FAILED;
4780 if (!MSI_RecordIsNull(row,5))
4782 INT index = MSI_RecordGetInteger(row,6);
4783 LPWSTR FileName = load_dynamic_stringW(row,5);
4784 LPWSTR FilePath,IconPath;
4785 static const WCHAR fmt[] = {'%','s',',','%','i',0};
4787 RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
4788 build_icon_path(package,FileName,&FilePath);
4790 IconPath = HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)*
4793 sprintfW(IconPath,fmt,FilePath,index);
4794 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)IconPath,
4795 (strlenW(IconPath)+1) * sizeof(WCHAR));
4796 HeapFree(GetProcessHeap(),0,FilePath);
4797 HeapFree(GetProcessHeap(),0,FileName);
4800 return ERROR_SUCCESS;
4803 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid);
4805 static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent,
4810 MSIRECORD * row = 0;
4811 static const WCHAR Query_t[] =
4812 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4813 'P','r','o','g' ,'I','d',' ','W','H','E','R','E',' ',
4814 'P','r','o','g','I','d',' ','=',' ','`' ,'%','s','`',0};
4817 return ERROR_INVALID_HANDLE;
4819 rc = MSI_OpenQuery(package->db, &view, Query_t, parent);
4820 if (rc != ERROR_SUCCESS)
4823 rc = MSI_ViewExecute(view, 0);
4824 if (rc != ERROR_SUCCESS)
4826 MSI_ViewClose(view);
4827 msiobj_release(&view->hdr);
4831 rc = MSI_ViewFetch(view,&row);
4832 if (rc != ERROR_SUCCESS)
4834 MSI_ViewClose(view);
4835 msiobj_release(&view->hdr);
4839 register_progid(package,row,clsid);
4841 msiobj_release(&row->hdr);
4842 MSI_ViewClose(view);
4843 msiobj_release(&view->hdr);
4847 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid)
4849 UINT rc = ERROR_SUCCESS;
4851 if (MSI_RecordIsNull(row,2))
4852 rc = register_progid_base(package,row,clsid);
4855 WCHAR buffer[0x1000];
4858 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
4859 static const WCHAR szDefaultIcon[] =
4860 {'D','e','f','a','u','l','t','I','c','o','n',0};
4862 /* check if already registered */
4864 MSI_RecordGetStringW(row,1,buffer,&sz);
4865 RegCreateKeyExW(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0,
4866 KEY_ALL_ACCESS, NULL, &hkey, &disp );
4867 if (disp == REG_OPENED_EXISTING_KEY)
4869 TRACE("Key already registered\n");
4875 MSI_RecordGetStringW(row,2,buffer,&sz);
4876 rc = register_parent_progid(package,buffer,clsid);
4878 /* clsid is same as parent */
4879 RegCreateKeyW(hkey,szCLSID,&hkey2);
4880 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
4886 if (!MSI_RecordIsNull(row,4))
4889 MSI_RecordGetStringW(row,4,buffer,&sz);
4890 RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer,
4891 (strlenW(buffer)+1) * sizeof(WCHAR));
4894 if (!MSI_RecordIsNull(row,5))
4896 LPWSTR FileName = load_dynamic_stringW(row,5);
4898 RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
4899 build_icon_path(package,FileName,&FilePath);
4900 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)FilePath,
4901 (strlenW(FilePath)+1) * sizeof(WCHAR));
4902 HeapFree(GetProcessHeap(),0,FilePath);
4903 HeapFree(GetProcessHeap(),0,FileName);
4912 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
4915 * Sigh, here I am just brute force registering all progids
4916 * this needs to be linked to the Classes that have been registered
4917 * but the easiest way to do that is to load all these stuff into
4918 * memory for easy checking.
4920 * Gives me something to continue to work toward.
4924 MSIRECORD * row = 0;
4925 static const WCHAR Query[] =
4926 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
4927 'P','r','o','g','I','d',0};
4930 return ERROR_INVALID_HANDLE;
4932 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4933 if (rc != ERROR_SUCCESS)
4934 return ERROR_SUCCESS;
4936 rc = MSI_ViewExecute(view, 0);
4937 if (rc != ERROR_SUCCESS)
4939 MSI_ViewClose(view);
4940 msiobj_release(&view->hdr);
4946 WCHAR clsid[0x1000];
4948 rc = MSI_ViewFetch(view,&row);
4949 if (rc != ERROR_SUCCESS)
4955 register_progid(package,row,clsid);
4956 ui_actiondata(package,szRegisterProgIdInfo,row);
4958 msiobj_release(&row->hdr);
4960 MSI_ViewClose(view);
4961 msiobj_release(&view->hdr);
4965 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name,
4969 LPWSTR SystemFolder;
4973 static const WCHAR szInstaller[] =
4974 {'I','n','s','t','a','l','l','e','r','\\',0};
4975 static const WCHAR szFolder[] =
4976 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
4978 ProductCode = load_dynamic_property(package,szProductCode,&rc);
4982 SystemFolder = load_dynamic_property(package,szFolder,NULL);
4984 dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);
4986 create_full_pathW(dest);
4988 *FilePath = build_directory_name(2, dest, icon_name);
4990 HeapFree(GetProcessHeap(),0,SystemFolder);
4991 HeapFree(GetProcessHeap(),0,ProductCode);
4992 HeapFree(GetProcessHeap(),0,dest);
4993 return ERROR_SUCCESS;
4996 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
5000 MSIRECORD * row = 0;
5001 static const WCHAR Query[] =
5002 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ',
5003 'S','h','o','r','t','c','u','t',0};
5009 return ERROR_INVALID_HANDLE;
5011 res = CoInitialize( NULL );
5014 ERR("CoInitialize failed\n");
5015 return ERROR_FUNCTION_FAILED;
5018 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
5019 if (rc != ERROR_SUCCESS)
5020 return ERROR_SUCCESS;
5022 rc = MSI_ViewExecute(view, 0);
5023 if (rc != ERROR_SUCCESS)
5025 MSI_ViewClose(view);
5026 msiobj_release(&view->hdr);
5032 LPWSTR target_file, target_folder;
5033 WCHAR buffer[0x100];
5036 static const WCHAR szlnk[]={'.','l','n','k',0};
5038 rc = MSI_ViewFetch(view,&row);
5039 if (rc != ERROR_SUCCESS)
5046 MSI_RecordGetStringW(row,4,buffer,&sz);
5048 index = get_loaded_component(package,buffer);
5052 msiobj_release(&row->hdr);
5056 if (!ACTION_VerifyComponentForAction(package, index,
5057 INSTALLSTATE_LOCAL))
5059 TRACE("Skipping shortcut creation due to disabled component\n");
5060 msiobj_release(&row->hdr);
5062 package->components[index].Action =
5063 package->components[index].Installed;
5068 package->components[index].Action = INSTALLSTATE_LOCAL;
5070 ui_actiondata(package,szCreateShortcuts,row);
5072 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
5073 &IID_IShellLinkW, (LPVOID *) &sl );
5077 ERR("Is IID_IShellLink\n");
5078 msiobj_release(&row->hdr);
5082 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
5085 ERR("Is IID_IPersistFile\n");
5086 msiobj_release(&row->hdr);
5091 MSI_RecordGetStringW(row,2,buffer,&sz);
5092 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
5094 /* may be needed because of a bug somehwere else */
5095 create_full_pathW(target_folder);
5098 MSI_RecordGetStringW(row,3,buffer,&sz);
5099 reduce_to_longfilename(buffer);
5100 if (!strchrW(buffer,'.') || strcmpiW(strchrW(buffer,'.'),szlnk))
5101 strcatW(buffer,szlnk);
5102 target_file = build_directory_name(2, target_folder, buffer);
5103 HeapFree(GetProcessHeap(),0,target_folder);
5106 MSI_RecordGetStringW(row,5,buffer,&sz);
5107 if (strchrW(buffer,'['))
5110 deformat_string(package,buffer,&deformated);
5111 IShellLinkW_SetPath(sl,deformated);
5112 HeapFree(GetProcessHeap(),0,deformated);
5117 FIXME("poorly handled shortcut format, advertised shortcut\n");
5118 keypath = strdupW(package->components[index].FullKeypath);
5119 IShellLinkW_SetPath(sl,keypath);
5120 HeapFree(GetProcessHeap(),0,keypath);
5123 if (!MSI_RecordIsNull(row,6))
5127 MSI_RecordGetStringW(row,6,buffer,&sz);
5128 deformat_string(package,buffer,&deformated);
5129 IShellLinkW_SetArguments(sl,deformated);
5130 HeapFree(GetProcessHeap(),0,deformated);
5133 if (!MSI_RecordIsNull(row,7))
5136 deformated = load_dynamic_stringW(row,7);
5137 IShellLinkW_SetDescription(sl,deformated);
5138 HeapFree(GetProcessHeap(),0,deformated);
5141 if (!MSI_RecordIsNull(row,8))
5142 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
5144 if (!MSI_RecordIsNull(row,9))
5150 MSI_RecordGetStringW(row,9,buffer,&sz);
5152 build_icon_path(package,buffer,&Path);
5153 index = MSI_RecordGetInteger(row,10);
5155 IShellLinkW_SetIconLocation(sl,Path,index);
5156 HeapFree(GetProcessHeap(),0,Path);
5159 if (!MSI_RecordIsNull(row,11))
5160 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
5162 if (!MSI_RecordIsNull(row,12))
5166 MSI_RecordGetStringW(row,12,buffer,&sz);
5167 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
5168 IShellLinkW_SetWorkingDirectory(sl,Path);
5169 HeapFree(GetProcessHeap(), 0, Path);
5172 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
5173 IPersistFile_Save(pf,target_file,FALSE);
5175 HeapFree(GetProcessHeap(),0,target_file);
5177 IPersistFile_Release( pf );
5178 IShellLinkW_Release( sl );
5180 msiobj_release(&row->hdr);
5182 MSI_ViewClose(view);
5183 msiobj_release(&view->hdr);
5193 * 99% of the work done here is only done for
5194 * advertised installs. However this is where the
5195 * Icon table is processed and written out
5196 * so that is what I am going to do here.
5198 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
5202 MSIRECORD * row = 0;
5203 static const WCHAR Query[]=
5204 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5207 /* for registry stuff */
5211 static const WCHAR szProductName[] =
5212 {'P','r','o','d','u','c','t','N','a','m','e',0};
5213 static const WCHAR szPackageCode[] =
5214 {'P','a','c','k','a','g','e','C','o','d','e',0};
5217 MSIHANDLE hDb, hSumInfo;
5220 return ERROR_INVALID_HANDLE;
5222 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
5223 if (rc != ERROR_SUCCESS)
5226 rc = MSI_ViewExecute(view, 0);
5227 if (rc != ERROR_SUCCESS)
5229 MSI_ViewClose(view);
5230 msiobj_release(&view->hdr);
5237 WCHAR *FilePath=NULL;
5238 WCHAR *FileName=NULL;
5241 rc = MSI_ViewFetch(view,&row);
5242 if (rc != ERROR_SUCCESS)
5248 FileName = load_dynamic_stringW(row,1);
5251 ERR("Unable to get FileName\n");
5252 msiobj_release(&row->hdr);
5256 build_icon_path(package,FileName,&FilePath);
5258 HeapFree(GetProcessHeap(),0,FileName);
5260 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
5262 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
5263 FILE_ATTRIBUTE_NORMAL, NULL);
5265 if (the_file == INVALID_HANDLE_VALUE)
5267 ERR("Unable to create file %s\n",debugstr_w(FilePath));
5268 msiobj_release(&row->hdr);
5269 HeapFree(GetProcessHeap(),0,FilePath);
5277 rc = MSI_RecordReadStream(row,2,buffer,&sz);
5278 if (rc != ERROR_SUCCESS)
5280 ERR("Failed to get stream\n");
5281 CloseHandle(the_file);
5282 DeleteFileW(FilePath);
5285 WriteFile(the_file,buffer,sz,&write,NULL);
5286 } while (sz == 1024);
5288 HeapFree(GetProcessHeap(),0,FilePath);
5290 CloseHandle(the_file);
5291 msiobj_release(&row->hdr);
5293 MSI_ViewClose(view);
5294 msiobj_release(&view->hdr);
5297 /* ok there is a lot more done here but i need to figure out what */
5298 productcode = load_dynamic_property(package,szProductCode,&rc);
5302 rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE);
5303 if (rc != ERROR_SUCCESS)
5306 rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
5307 if (rc != ERROR_SUCCESS)
5311 buffer = load_dynamic_property(package,szProductName,NULL);
5312 size = strlenW(buffer)*sizeof(WCHAR);
5313 RegSetValueExW(hukey,szProductName,0,REG_SZ, (LPSTR)buffer,size);
5314 HeapFree(GetProcessHeap(),0,buffer);
5315 FIXME("Need to write more keys to the user registry\n");
5317 hDb= alloc_msihandle( &package->db->hdr );
5318 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
5319 MsiCloseHandle(hDb);
5320 if (rc == ERROR_SUCCESS)
5322 WCHAR guidbuffer[0x200];
5324 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
5326 if (rc == ERROR_SUCCESS)
5328 WCHAR squashed[GUID_SIZE];
5329 /* for now we only care about the first guid */
5330 LPWSTR ptr = strchrW(guidbuffer,';');
5332 squash_guid(guidbuffer,squashed);
5333 size = strlenW(squashed)*sizeof(WCHAR);
5334 RegSetValueExW(hukey,szPackageCode,0,REG_SZ, (LPSTR)squashed,
5339 ERR("Unable to query Revision_Number... \n");
5342 MsiCloseHandle(hSumInfo);
5346 ERR("Unable to open Summary Information\n");
5352 HeapFree(GetProcessHeap(),0,productcode);
5359 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
5363 MSIRECORD * row = 0;
5364 static const WCHAR ExecSeqQuery[] =
5365 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5366 'I','n','i','F','i','l','e',0};
5367 static const WCHAR szWindowsFolder[] =
5368 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
5370 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5371 if (rc != ERROR_SUCCESS)
5373 TRACE("no IniFile table\n");
5374 return ERROR_SUCCESS;
5377 rc = MSI_ViewExecute(view, 0);
5378 if (rc != ERROR_SUCCESS)
5380 MSI_ViewClose(view);
5381 msiobj_release(&view->hdr);
5387 LPWSTR component,filename,dirproperty,section,key,value,identifier;
5388 LPWSTR deformated_section, deformated_key, deformated_value;
5389 LPWSTR folder, fullname = NULL;
5391 INT component_index,action;
5393 rc = MSI_ViewFetch(view,&row);
5394 if (rc != ERROR_SUCCESS)
5400 component = load_dynamic_stringW(row, 8);
5401 component_index = get_loaded_component(package,component);
5402 HeapFree(GetProcessHeap(),0,component);
5404 if (!ACTION_VerifyComponentForAction(package, component_index,
5405 INSTALLSTATE_LOCAL))
5407 TRACE("Skipping ini file due to disabled component\n");
5408 msiobj_release(&row->hdr);
5410 package->components[component_index].Action =
5411 package->components[component_index].Installed;
5416 package->components[component_index].Action = INSTALLSTATE_LOCAL;
5418 identifier = load_dynamic_stringW(row,1);
5419 filename = load_dynamic_stringW(row,2);
5420 dirproperty = load_dynamic_stringW(row,3);
5421 section = load_dynamic_stringW(row,4);
5422 key = load_dynamic_stringW(row,5);
5423 value = load_dynamic_stringW(row,6);
5424 action = MSI_RecordGetInteger(row,7);
5426 deformat_string(package,section,&deformated_section);
5427 deformat_string(package,key,&deformated_key);
5428 deformat_string(package,value,&deformated_value);
5432 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
5434 folder = load_dynamic_property(package,dirproperty,NULL);
5437 folder = load_dynamic_property(package, szWindowsFolder, NULL);
5441 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
5445 fullname = build_directory_name(3, folder, filename, NULL);
5449 TRACE("Adding value %s to section %s in %s\n",
5450 debugstr_w(deformated_key), debugstr_w(deformated_section),
5451 debugstr_w(fullname));
5452 WritePrivateProfileStringW(deformated_section, deformated_key,
5453 deformated_value, fullname);
5455 else if (action == 1)
5458 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
5459 returned, 10, fullname);
5460 if (returned[0] == 0)
5462 TRACE("Adding value %s to section %s in %s\n",
5463 debugstr_w(deformated_key), debugstr_w(deformated_section),
5464 debugstr_w(fullname));
5466 WritePrivateProfileStringW(deformated_section, deformated_key,
5467 deformated_value, fullname);
5470 else if (action == 3)
5472 FIXME("Append to existing section not yet implemented\n");
5475 uirow = MSI_CreateRecord(4);
5476 MSI_RecordSetStringW(uirow,1,identifier);
5477 MSI_RecordSetStringW(uirow,2,deformated_section);
5478 MSI_RecordSetStringW(uirow,3,deformated_key);
5479 MSI_RecordSetStringW(uirow,4,deformated_value);
5480 ui_actiondata(package,szWriteIniValues,uirow);
5481 msiobj_release( &uirow->hdr );
5483 HeapFree(GetProcessHeap(),0,identifier);
5484 HeapFree(GetProcessHeap(),0,fullname);
5485 HeapFree(GetProcessHeap(),0,filename);
5486 HeapFree(GetProcessHeap(),0,key);
5487 HeapFree(GetProcessHeap(),0,value);
5488 HeapFree(GetProcessHeap(),0,section);
5489 HeapFree(GetProcessHeap(),0,dirproperty);
5490 HeapFree(GetProcessHeap(),0,folder);
5491 HeapFree(GetProcessHeap(),0,deformated_key);
5492 HeapFree(GetProcessHeap(),0,deformated_value);
5493 HeapFree(GetProcessHeap(),0,deformated_section);
5494 msiobj_release(&row->hdr);
5496 MSI_ViewClose(view);
5497 msiobj_release(&view->hdr);
5501 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
5505 MSIRECORD * row = 0;
5506 static const WCHAR ExecSeqQuery[] =
5507 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5508 'S','e','l','f','R','e','g',0};
5510 static const WCHAR ExeStr[] =
5511 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
5512 static const WCHAR close[] = {'\"',0};
5514 PROCESS_INFORMATION info;
5517 memset(&si,0,sizeof(STARTUPINFOW));
5519 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5520 if (rc != ERROR_SUCCESS)
5522 TRACE("no SelfReg table\n");
5523 return ERROR_SUCCESS;
5526 rc = MSI_ViewExecute(view, 0);
5527 if (rc != ERROR_SUCCESS)
5529 MSI_ViewClose(view);
5530 msiobj_release(&view->hdr);
5540 rc = MSI_ViewFetch(view,&row);
5541 if (rc != ERROR_SUCCESS)
5547 filename = load_dynamic_stringW(row,1);
5548 index = get_loaded_file(package,filename);
5552 ERR("Unable to find file id %s\n",debugstr_w(filename));
5553 HeapFree(GetProcessHeap(),0,filename);
5554 msiobj_release(&row->hdr);
5557 HeapFree(GetProcessHeap(),0,filename);
5559 len = strlenW(ExeStr);
5560 len += strlenW(package->files[index].TargetPath);
5563 filename = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
5564 strcpyW(filename,ExeStr);
5565 strcatW(filename,package->files[index].TargetPath);
5566 strcatW(filename,close);
5568 TRACE("Registering %s\n",debugstr_w(filename));
5569 brc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL,
5570 c_colon, &si, &info);
5573 msi_dialog_check_messages(info.hProcess);
5575 HeapFree(GetProcessHeap(),0,filename);
5576 msiobj_release(&row->hdr);
5578 MSI_ViewClose(view);
5579 msiobj_release(&view->hdr);
5583 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
5592 return ERROR_INVALID_HANDLE;
5594 productcode = load_dynamic_property(package,szProductCode,&rc);
5598 rc = MSIREG_OpenFeaturesKey(productcode,&hkey,TRUE);
5599 if (rc != ERROR_SUCCESS)
5602 rc = MSIREG_OpenUserFeaturesKey(productcode,&hukey,TRUE);
5603 if (rc != ERROR_SUCCESS)
5606 /* here the guids are base 85 encoded */
5607 for (i = 0; i < package->loaded_features; i++)
5613 BOOL absent = FALSE;
5615 if (!ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_LOCAL) &&
5616 !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_SOURCE) &&
5617 !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_ADVERTISED))
5620 size = package->features[i].ComponentCount*21;
5622 if (package->features[i].Feature_Parent[0])
5623 size += strlenW(package->features[i].Feature_Parent)+2;
5625 data = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5628 for (j = 0; j < package->features[i].ComponentCount; j++)
5631 memset(buf,0,sizeof(buf));
5632 if (package->components
5633 [package->features[i].Components[j]].ComponentId[0]!=0)
5635 TRACE("From %s\n",debugstr_w(package->components
5636 [package->features[i].Components[j]].ComponentId));
5637 CLSIDFromString(package->components
5638 [package->features[i].Components[j]].ComponentId,
5640 encode_base85_guid(&clsid,buf);
5641 TRACE("to %s\n",debugstr_w(buf));
5645 if (package->features[i].Feature_Parent[0])
5647 static const WCHAR sep[] = {'\2',0};
5649 strcatW(data,package->features[i].Feature_Parent);
5652 size = (strlenW(data)+1)*sizeof(WCHAR);
5653 RegSetValueExW(hkey,package->features[i].Feature,0,REG_SZ,
5655 HeapFree(GetProcessHeap(),0,data);
5659 size = strlenW(package->features[i].Feature_Parent)*sizeof(WCHAR);
5660 RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,
5661 (LPSTR)package->features[i].Feature_Parent,size);
5665 size = (strlenW(package->features[i].Feature_Parent)+2)*
5667 data = HeapAlloc(GetProcessHeap(),0,size);
5669 strcpyW(&data[1],package->features[i].Feature_Parent);
5670 RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,
5672 HeapFree(GetProcessHeap(),0,data);
5679 HeapFree(GetProcessHeap(), 0, productcode);
5683 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
5690 static WCHAR szNONE[] = {0};
5691 static const WCHAR szWindowsInstaler[] =
5692 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
5693 static const WCHAR szPropKeys[][80] =
5695 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0},
5696 {'A','R','P','C','O','N','T','A','C','T',0},
5697 {'A','R','P','C','O','M','M','E','N','T','S',0},
5698 {'P','r','o','d','u','c','t','N','a','m','e',0},
5699 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0},
5700 {'A','R','P','H','E','L','P','L','I','N','K',0},
5701 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0},
5702 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0},
5703 {'S','o','u','r','c','e','D','i','r',0},
5704 {'M','a','n','u','f','a','c','t','u','r','e','r',0},
5705 {'A','R','P','R','E','A','D','M','E',0},
5706 {'A','R','P','S','I','Z','E',0},
5707 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0},
5708 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0},
5712 static const WCHAR szRegKeys[][80] =
5714 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0},
5715 {'C','o','n','t','a','c','t',0},
5716 {'C','o','m','m','e','n','t','s',0},
5717 {'D','i','s','p','l','a','y','N','a','m','e',0},
5718 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0},
5719 {'H','e','l','p','L','i','n','k',0},
5720 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0},
5721 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0},
5722 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0},
5723 {'P','u','b','l','i','s','h','e','r',0},
5724 {'R','e','a','d','m','e',0},
5725 {'S','i','z','e',0},
5726 {'U','R','L','I','n','f','o','A','b','o','u','t',0},
5727 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0},
5731 static const WCHAR installerPathFmt[] = {
5733 'I','n','s','t','a','l','l','e','r','\\',0};
5734 static const WCHAR fmt[] = {
5736 'I','n','s','t','a','l','l','e','r','\\',
5737 '%','x','.','m','s','i',0};
5738 static const WCHAR szLocalPackage[]=
5739 {'L','o','c','a','l','P','a','c','k','a','g','e',0};
5740 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
5744 return ERROR_INVALID_HANDLE;
5746 productcode = load_dynamic_property(package,szProductCode,&rc);
5750 rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
5751 if (rc != ERROR_SUCCESS)
5754 /* dump all the info i can grab */
5755 FIXME("Flesh out more information \n");
5758 while (szPropKeys[i][0]!=0)
5760 buffer = load_dynamic_property(package,szPropKeys[i],&rc);
5761 if (rc != ERROR_SUCCESS)
5763 size = strlenW(buffer)*sizeof(WCHAR);
5764 RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);
5770 RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPSTR)&rc,size);
5772 /* copy the package locally */
5773 num = GetTickCount() & 0xffff;
5777 GetWindowsDirectoryW(windir, sizeof(windir) / sizeof(windir[0]));
5778 snprintfW(packagefile,sizeof(packagefile)/sizeof(packagefile[0]),fmt,
5782 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
5783 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
5784 if (handle != INVALID_HANDLE_VALUE)
5786 CloseHandle(handle);
5789 if (GetLastError() != ERROR_FILE_EXISTS &&
5790 GetLastError() != ERROR_SHARING_VIOLATION)
5792 if (!(++num & 0xffff)) num = 1;
5793 sprintfW(packagefile,fmt,num);
5794 } while (num != start);
5796 snprintfW(path,sizeof(path)/sizeof(path[0]),installerPathFmt,windir);
5797 create_full_pathW(path);
5798 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
5799 if (!CopyFileW(package->PackagePath,packagefile,FALSE))
5800 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
5801 debugstr_w(package->PackagePath), debugstr_w(packagefile),
5803 size = strlenW(packagefile)*sizeof(WCHAR);
5804 RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size);
5807 HeapFree(GetProcessHeap(),0,productcode);
5810 return ERROR_SUCCESS;
5813 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5817 return ERROR_INVALID_HANDLE;
5819 for (i = 0; i < package->DeferredActionCount; i++)
5822 action = package->DeferredAction[i];
5823 ui_actionstart(package, action);
5824 TRACE("Executing Action (%s)\n",debugstr_w(action));
5825 ACTION_CustomAction(package,action,TRUE);
5826 HeapFree(GetProcessHeap(),0,package->DeferredAction[i]);
5828 HeapFree(GetProcessHeap(),0,package->DeferredAction);
5830 package->DeferredActionCount = 0;
5831 package->DeferredAction = NULL;
5833 return ERROR_SUCCESS;
5836 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5840 return ERROR_INVALID_HANDLE;
5842 /* first do the same as an InstallExecute */
5843 ACTION_InstallExecute(package);
5845 /* then handle Commit Actions */
5846 for (i = 0; i < package->CommitActionCount; i++)
5849 action = package->CommitAction[i];
5850 ui_actionstart(package, action);
5851 TRACE("Executing Commit Action (%s)\n",debugstr_w(action));
5852 ACTION_CustomAction(package,action,TRUE);
5853 HeapFree(GetProcessHeap(),0,package->CommitAction[i]);
5855 HeapFree(GetProcessHeap(),0,package->CommitAction);
5857 package->CommitActionCount = 0;
5858 package->CommitAction = NULL;
5860 return ERROR_SUCCESS;
5863 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
5865 static const WCHAR RunOnce[] = {
5866 'S','o','f','t','w','a','r','e','\\',
5867 'M','i','c','r','o','s','o','f','t','\\',
5868 'W','i','n','d','o','w','s','\\',
5869 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5870 'R','u','n','O','n','c','e',0};
5871 static const WCHAR InstallRunOnce[] = {
5872 'S','o','f','t','w','a','r','e','\\',
5873 'M','i','c','r','o','s','o','f','t','\\',
5874 'W','i','n','d','o','w','s','\\',
5875 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5876 'I','n','s','t','a','l','l','e','r','\\',
5877 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5879 static const WCHAR msiexec_fmt[] = {
5881 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5882 '\"','%','s','\"',0};
5883 static const WCHAR install_fmt[] = {
5884 '/','I',' ','\"','%','s','\"',' ',
5885 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5886 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5887 WCHAR buffer[256], sysdir[MAX_PATH];
5890 WCHAR squished_pc[100];
5893 static const WCHAR szLUS[] = {
5894 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0};
5895 static const WCHAR szSourceList[] = {
5896 'S','o','u','r','c','e','L','i','s','t',0};
5897 static const WCHAR szPackageName[] = {
5898 'P','a','c','k','a','g','e','N','a','m','e',0};
5901 return ERROR_INVALID_HANDLE;
5903 productcode = load_dynamic_property(package,szProductCode,&rc);
5907 squash_guid(productcode,squished_pc);
5909 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5910 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5911 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5914 size = strlenW(buffer)*sizeof(WCHAR);
5915 RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
5918 TRACE("Reboot command %s\n",debugstr_w(buffer));
5920 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5921 sprintfW(buffer,install_fmt,productcode,squished_pc);
5923 size = strlenW(buffer)*sizeof(WCHAR);
5924 RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
5927 rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
5928 if (rc == ERROR_SUCCESS)
5932 RegCreateKeyW(hukey, szSourceList, &hukey2);
5933 buf = load_dynamic_property(package,cszSourceDir,NULL);
5934 size = strlenW(buf)*sizeof(WCHAR);
5935 RegSetValueExW(hukey2,szLUS,0,REG_SZ,(LPSTR)buf,size);
5936 HeapFree(GetProcessHeap(),0,buf);
5938 buf = strrchrW(package->PackagePath,'\\');
5942 size = strlenW(buf)*sizeof(WCHAR);
5943 RegSetValueExW(hukey2,szPackageName,0,REG_SZ,(LPSTR)buf,size);
5946 RegCloseKey(hukey2);
5948 HeapFree(GetProcessHeap(),0,productcode);
5950 return ERROR_INSTALL_SUSPEND;
5953 UINT ACTION_ResolveSource(MSIPACKAGE* package)
5956 * we are currently doing what should be done here in the top level Install
5957 * however for Adminastrative and uninstalls this step will be needed
5959 return ERROR_SUCCESS;
5963 static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
5967 MSIRECORD * row = 0;
5968 static const WCHAR ExecSeqQuery[] =
5969 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5970 'E','x','t','e','n','s','i','o','n',0};
5971 static const WCHAR szContentType[] =
5972 {'C','o','n','t','e','n','t',' ','T','y','p','e',0 };
5976 return ERROR_INVALID_HANDLE;
5978 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5979 if (rc != ERROR_SUCCESS)
5985 rc = MSI_ViewExecute(view, 0);
5986 if (rc != ERROR_SUCCESS)
5988 MSI_ViewClose(view);
5989 msiobj_release(&view->hdr);
5995 WCHAR buffer[0x100];
5996 WCHAR extension[257];
6001 rc = MSI_ViewFetch(view,&row);
6002 if (rc != ERROR_SUCCESS)
6009 MSI_RecordGetStringW(row,2,buffer,&sz);
6011 index = get_loaded_component(package,buffer);
6015 msiobj_release(&row->hdr);
6019 if (!ACTION_VerifyComponentForAction(package, index,
6020 INSTALLSTATE_LOCAL))
6022 TRACE("Skipping extension reg due to disabled component\n");
6023 msiobj_release(&row->hdr);
6025 package->components[index].Action =
6026 package->components[index].Installed;
6031 package->components[index].Action = INSTALLSTATE_LOCAL;
6033 exten = load_dynamic_stringW(row,1);
6036 strcatW(extension,exten);
6037 HeapFree(GetProcessHeap(),0,exten);
6039 RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey);
6041 if (!MSI_RecordIsNull(row,4))
6043 LPWSTR mime = load_dynamic_stringW(row,4);
6044 RegSetValueExW(hkey,szContentType,0,REG_SZ,(LPVOID)mime,
6045 (strlenW(mime)+1)*sizeof(WCHAR));
6046 HeapFree(GetProcessHeap(),0,mime);
6049 if (!MSI_RecordIsNull(row,3))
6051 static const WCHAR szSN[] =
6052 {'\\','S','h','e','l','l','N','e','w',0};
6055 LPWSTR progid= load_dynamic_stringW(row,3);
6057 RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid,
6058 (strlenW(progid)+1)*sizeof(WCHAR));
6060 newkey = HeapAlloc(GetProcessHeap(),0,
6061 (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR));
6063 strcpyW(newkey,progid);
6064 strcatW(newkey,szSN);
6065 RegCreateKeyW(hkey,newkey,&hkey2);
6068 HeapFree(GetProcessHeap(),0,progid);
6069 HeapFree(GetProcessHeap(),0,newkey);
6075 ui_actiondata(package,szRegisterExtensionInfo,row);
6077 msiobj_release(&row->hdr);
6079 MSI_ViewClose(view);
6080 msiobj_release(&view->hdr);
6086 static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
6090 MSIRECORD * row = 0;
6091 static const WCHAR ExecSeqQuery[] =
6092 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6094 static const WCHAR szExten[] =
6095 {'E','x','t','e','n','s','i','o','n',0 };
6099 return ERROR_INVALID_HANDLE;
6101 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6102 if (rc != ERROR_SUCCESS)
6108 rc = MSI_ViewExecute(view, 0);
6109 if (rc != ERROR_SUCCESS)
6111 MSI_ViewClose(view);
6112 msiobj_release(&view->hdr);
6118 WCHAR extension[257];
6121 static const WCHAR fmt[] =
6122 {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
6123 'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0};
6126 rc = MSI_ViewFetch(view,&row);
6127 if (rc != ERROR_SUCCESS)
6133 mime = load_dynamic_stringW(row,1);
6134 exten = load_dynamic_stringW(row,2);
6137 strcatW(extension,exten);
6138 HeapFree(GetProcessHeap(),0,exten);
6140 key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) *
6142 sprintfW(key,fmt,mime);
6143 RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey);
6144 RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension,
6145 (strlenW(extension)+1)*sizeof(WCHAR));
6147 HeapFree(GetProcessHeap(),0,mime);
6148 HeapFree(GetProcessHeap(),0,key);
6150 if (!MSI_RecordIsNull(row,3))
6152 FIXME("Handle non null for field 3\n");
6157 ui_actiondata(package,szRegisterMIMEInfo,row);
6159 msiobj_release(&row->hdr);
6161 MSI_ViewClose(view);
6162 msiobj_release(&view->hdr);
6168 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
6170 static const WCHAR szProductID[]=
6171 {'P','r','o','d','u','c','t','I','D',0};
6179 static const WCHAR szPropKeys[][80] =
6181 {'P','r','o','d','u','c','t','I','D',0},
6182 {'U','S','E','R','N','A','M','E',0},
6183 {'C','O','M','P','A','N','Y','N','A','M','E',0},
6187 static const WCHAR szRegKeys[][80] =
6189 {'P','r','o','d','u','c','t','I','D',0},
6190 {'R','e','g','O','w','n','e','r',0},
6191 {'R','e','g','C','o','m','p','a','n','y',0},
6196 return ERROR_INVALID_HANDLE;
6198 productid = load_dynamic_property(package,szProductID,&rc);
6200 return ERROR_SUCCESS;
6202 productcode = load_dynamic_property(package,szProductCode,&rc);
6206 rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
6207 if (rc != ERROR_SUCCESS)
6211 while (szPropKeys[i][0]!=0)
6213 buffer = load_dynamic_property(package,szPropKeys[i],&rc);
6214 if (rc == ERROR_SUCCESS)
6216 size = strlenW(buffer)*sizeof(WCHAR);
6217 RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);
6223 HeapFree(GetProcessHeap(),0,productcode);
6224 HeapFree(GetProcessHeap(),0,productid);
6227 return ERROR_SUCCESS;
6231 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
6234 rc = ACTION_ProcessExecSequence(package,FALSE);
6240 * Code based off of code located here
6241 * http://www.codeproject.com/gdi/fontnamefromfile.asp
6243 * Using string index 4 (full font name) instead of 1 (family name)
6245 static LPWSTR load_ttfname_from(LPCWSTR filename)
6251 typedef struct _tagTT_OFFSET_TABLE{
6252 USHORT uMajorVersion;
6253 USHORT uMinorVersion;
6254 USHORT uNumOfTables;
6255 USHORT uSearchRange;
6256 USHORT uEntrySelector;
6260 typedef struct _tagTT_TABLE_DIRECTORY{
6261 char szTag[4]; /* table name */
6262 ULONG uCheckSum; /* Check sum */
6263 ULONG uOffset; /* Offset from beginning of file */
6264 ULONG uLength; /* length of the table in bytes */
6265 }TT_TABLE_DIRECTORY;
6267 typedef struct _tagTT_NAME_TABLE_HEADER{
6268 USHORT uFSelector; /* format selector. Always 0 */
6269 USHORT uNRCount; /* Name Records count */
6270 USHORT uStorageOffset; /* Offset for strings storage,
6271 * from start of the table */
6272 }TT_NAME_TABLE_HEADER;
6274 typedef struct _tagTT_NAME_RECORD{
6279 USHORT uStringLength;
6280 USHORT uStringOffset; /* from start of storage area */
6283 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
6284 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
6286 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
6287 FILE_ATTRIBUTE_NORMAL, 0 );
6288 if (handle != INVALID_HANDLE_VALUE)
6290 TT_TABLE_DIRECTORY tblDir;
6291 BOOL bFound = FALSE;
6292 TT_OFFSET_TABLE ttOffsetTable;
6294 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),NULL,NULL);
6295 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
6296 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
6297 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
6299 if (ttOffsetTable.uMajorVersion != 1 ||
6300 ttOffsetTable.uMinorVersion != 0)
6303 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
6305 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),NULL,NULL);
6306 if (strncmp(tblDir.szTag,"name",4)==0)
6309 tblDir.uLength = SWAPLONG(tblDir.uLength);
6310 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
6317 TT_NAME_TABLE_HEADER ttNTHeader;
6318 TT_NAME_RECORD ttRecord;
6320 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
6321 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
6324 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
6325 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
6327 for(i=0; i<ttNTHeader.uNRCount; i++)
6329 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),NULL,NULL);
6330 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
6331 /* 4 is the Full Font Name */
6332 if(ttRecord.uNameID == 4)
6336 static const LPSTR tt = " (TrueType)";
6338 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
6339 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
6340 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
6341 SetFilePointer(handle, tblDir.uOffset +
6342 ttRecord.uStringOffset +
6343 ttNTHeader.uStorageOffset,
6345 buf = HeapAlloc(GetProcessHeap(), 0,
6346 ttRecord.uStringLength + 1 + strlen(tt));
6347 memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
6348 ReadFile(handle, buf, ttRecord.uStringLength, NULL, NULL);
6349 if (strlen(buf) > 0)
6352 ret = strdupAtoW(buf);
6353 HeapFree(GetProcessHeap(),0,buf);
6357 HeapFree(GetProcessHeap(),0,buf);
6358 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
6362 CloseHandle(handle);
6365 ERR("Unable to open font file %s\n", debugstr_w(filename));
6367 TRACE("Returning fontname %s\n",debugstr_w(ret));
6371 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
6375 MSIRECORD * row = 0;
6376 static const WCHAR ExecSeqQuery[] =
6377 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6379 static const WCHAR regfont1[] =
6380 {'S','o','f','t','w','a','r','e','\\',
6381 'M','i','c','r','o','s','o','f','t','\\',
6382 'W','i','n','d','o','w','s',' ','N','T','\\',
6383 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
6384 'F','o','n','t','s',0};
6385 static const WCHAR regfont2[] =
6386 {'S','o','f','t','w','a','r','e','\\',
6387 'M','i','c','r','o','s','o','f','t','\\',
6388 'W','i','n','d','o','w','s','\\',
6389 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
6390 'F','o','n','t','s',0};
6394 TRACE("%p\n", package);
6396 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6397 if (rc != ERROR_SUCCESS)
6399 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
6400 return ERROR_SUCCESS;
6403 rc = MSI_ViewExecute(view, 0);
6404 if (rc != ERROR_SUCCESS)
6406 MSI_ViewClose(view);
6407 msiobj_release(&view->hdr);
6408 TRACE("MSI_ViewExecute returned %d\n", rc);
6409 return ERROR_SUCCESS;
6412 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
6413 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
6422 rc = MSI_ViewFetch(view,&row);
6423 if (rc != ERROR_SUCCESS)
6429 file = load_dynamic_stringW(row,1);
6430 index = get_loaded_file(package,file);
6433 ERR("Unable to load file\n");
6434 HeapFree(GetProcessHeap(),0,file);
6438 /* check to make sure that component is installed */
6439 if (!ACTION_VerifyComponentForAction(package,
6440 package->files[index].ComponentIndex, INSTALLSTATE_LOCAL))
6442 TRACE("Skipping: Component not scheduled for install\n");
6443 HeapFree(GetProcessHeap(),0,file);
6445 msiobj_release(&row->hdr);
6450 if (MSI_RecordIsNull(row,2))
6451 name = load_ttfname_from(package->files[index].TargetPath);
6453 name = load_dynamic_stringW(row,2);
6457 size = strlenW(package->files[index].FileName) * sizeof(WCHAR);
6458 RegSetValueExW(hkey1,name,0,REG_SZ,
6459 (LPBYTE)package->files[index].FileName,size);
6460 RegSetValueExW(hkey2,name,0,REG_SZ,
6461 (LPBYTE)package->files[index].FileName,size);
6464 HeapFree(GetProcessHeap(),0,file);
6465 HeapFree(GetProcessHeap(),0,name);
6466 msiobj_release(&row->hdr);
6468 MSI_ViewClose(view);
6469 msiobj_release(&view->hdr);
6474 TRACE("returning %d\n", rc);
6478 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
6480 MSIPACKAGE *package = (MSIPACKAGE*)param;
6481 LPWSTR productid=NULL, compgroupid=NULL;
6482 LPWSTR feature=NULL;
6484 LPWSTR qualifier = NULL;
6485 LPWSTR component = NULL;
6487 WCHAR productid_85[21];
6488 WCHAR component_85[21];
6490 UINT rc = ERROR_SUCCESS;
6493 * I have a fair bit of confusion as to when a < is used and when a > is
6494 * used. I do not think i have it right...
6496 * Ok it appears that the > is used if there is a guid for the compoenent
6497 * and the < is used if not.
6499 static WCHAR fmt1[] = {'%','s','%','s','<',0,0};
6500 static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0};
6501 LPWSTR output = NULL;
6503 INT component_index;
6505 component = load_dynamic_stringW(rec,3);
6506 component_index = get_loaded_component(package,component);
6508 if (!ACTION_VerifyComponentForAction(package, component_index,
6509 INSTALLSTATE_LOCAL) &&
6510 !ACTION_VerifyComponentForAction(package, component_index,
6511 INSTALLSTATE_SOURCE) &&
6512 !ACTION_VerifyComponentForAction(package, component_index,
6513 INSTALLSTATE_ADVERTISED))
6515 TRACE("Skipping: Component %s not scheduled for install\n",
6516 debugstr_w(component));
6517 HeapFree(GetProcessHeap(),0,component);
6518 return ERROR_SUCCESS;
6521 memset(productid_85,0,sizeof(productid_85));
6522 memset(component_85,0,sizeof(component_85));
6523 compgroupid = load_dynamic_stringW(rec,1);
6525 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
6526 if (rc != ERROR_SUCCESS)
6529 productid = load_dynamic_property(package,szProductCode,NULL);
6530 CLSIDFromString(productid, &clsid);
6532 encode_base85_guid(&clsid,productid_85);
6534 text = load_dynamic_stringW(rec,4);
6535 qualifier = load_dynamic_stringW(rec,2);
6537 feature = load_dynamic_stringW(rec,5);
6539 index = get_loaded_component(package, component);
6540 CLSIDFromString(package->components[index].ComponentId, &clsid);
6541 encode_base85_guid(&clsid,component_85);
6543 TRACE("Doing something with this... %s = %s %s %s %s\n",
6544 debugstr_w(qualifier), debugstr_w(productid_85),
6545 debugstr_w(feature), debugstr_w(text), debugstr_w(component_85));
6547 sz = lstrlenW(productid_85) + lstrlenW(feature);
6549 sz += lstrlenW(text);
6550 if (component && index >= 0)
6551 sz += lstrlenW(component_85);
6554 sz *= sizeof(WCHAR);
6556 output = HeapAlloc(GetProcessHeap(),0,sz);
6557 memset(output,0,sz);
6559 if (component && index >= 0)
6560 sprintfW(output,fmt2,productid_85,feature,component_85);
6562 sprintfW(output,fmt1,productid_85,feature);
6565 strcatW(output,text);
6567 sz = (lstrlenW(output)+2) * sizeof(WCHAR);
6568 RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz);
6572 HeapFree(GetProcessHeap(),0,output);
6573 HeapFree(GetProcessHeap(),0,compgroupid);
6574 HeapFree(GetProcessHeap(),0,component);
6575 HeapFree(GetProcessHeap(),0,productid);
6576 HeapFree(GetProcessHeap(),0,feature);
6577 HeapFree(GetProcessHeap(),0,text);
6578 HeapFree(GetProcessHeap(),0,qualifier);
6584 * At present I am ignorning the advertised components part of this and only
6585 * focusing on the qualified component sets
6587 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
6591 static const WCHAR ExecSeqQuery[] =
6592 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6593 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0};
6595 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6596 if (rc != ERROR_SUCCESS)
6597 return ERROR_SUCCESS;
6599 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
6600 msiobj_release(&view->hdr);
6605 /* Msi functions that seem appropriate here */
6607 /***********************************************************************
6608 * MsiDoActionA (MSI.@)
6610 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
6615 TRACE(" exteral attempt at action %s\n",szAction);
6618 return ERROR_FUNCTION_FAILED;
6620 return ERROR_FUNCTION_FAILED;
6622 szwAction = strdupAtoW(szAction);
6625 return ERROR_FUNCTION_FAILED;
6628 rc = MsiDoActionW(hInstall, szwAction);
6629 HeapFree(GetProcessHeap(),0,szwAction);
6633 /***********************************************************************
6634 * MsiDoActionW (MSI.@)
6636 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
6638 MSIPACKAGE *package;
6639 UINT ret = ERROR_INVALID_HANDLE;
6641 TRACE(" external attempt at action %s \n",debugstr_w(szAction));
6643 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
6646 ret = ACTION_PerformUIAction(package,szAction);
6647 msiobj_release( &package->hdr );
6652 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
6653 LPSTR szPathBuf, DWORD* pcchPathBuf)
6659 TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
6662 return ERROR_FUNCTION_FAILED;
6664 return ERROR_FUNCTION_FAILED;
6666 szwFolder = strdupAtoW(szFolder);
6669 return ERROR_FUNCTION_FAILED;
6671 szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
6673 rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
6675 WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
6676 *pcchPathBuf, NULL, NULL );
6678 HeapFree(GetProcessHeap(),0,szwFolder);
6679 HeapFree(GetProcessHeap(),0,szwPathBuf);
6684 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
6685 szPathBuf, DWORD* pcchPathBuf)
6688 UINT rc = ERROR_FUNCTION_FAILED;
6689 MSIPACKAGE *package;
6691 TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
6693 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
6695 return ERROR_INVALID_HANDLE;
6696 path = resolve_folder(package, szFolder, FALSE, FALSE, NULL);
6697 msiobj_release( &package->hdr );
6699 if (path && (strlenW(path) > *pcchPathBuf))
6701 *pcchPathBuf = strlenW(path)+1;
6702 rc = ERROR_MORE_DATA;
6706 *pcchPathBuf = strlenW(path)+1;
6707 strcpyW(szPathBuf,path);
6708 TRACE("Returning Path %s\n",debugstr_w(path));
6711 HeapFree(GetProcessHeap(),0,path);
6717 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder,
6718 LPSTR szPathBuf, DWORD* pcchPathBuf)
6724 TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
6727 return ERROR_FUNCTION_FAILED;
6729 return ERROR_FUNCTION_FAILED;
6731 szwFolder = strdupAtoW(szFolder);
6733 return ERROR_FUNCTION_FAILED;
6735 szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
6737 rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
6739 WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
6740 *pcchPathBuf, NULL, NULL );
6742 HeapFree(GetProcessHeap(),0,szwFolder);
6743 HeapFree(GetProcessHeap(),0,szwPathBuf);
6748 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
6749 szPathBuf, DWORD* pcchPathBuf)
6752 UINT rc = ERROR_FUNCTION_FAILED;
6753 MSIPACKAGE *package;
6755 TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
6757 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
6759 return ERROR_INVALID_HANDLE;
6760 path = resolve_folder(package, szFolder, TRUE, FALSE, NULL);
6761 msiobj_release( &package->hdr );
6763 if (path && strlenW(path) > *pcchPathBuf)
6765 *pcchPathBuf = strlenW(path)+1;
6766 rc = ERROR_MORE_DATA;
6770 *pcchPathBuf = strlenW(path)+1;
6771 strcpyW(szPathBuf,path);
6772 TRACE("Returning Path %s\n",debugstr_w(path));
6775 HeapFree(GetProcessHeap(),0,path);
6781 /***********************************************************************
6782 * MsiSetTargetPathA (MSI.@)
6784 UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder,
6785 LPCSTR szFolderPath)
6788 LPWSTR szwFolderPath;
6792 return ERROR_FUNCTION_FAILED;
6794 return ERROR_FUNCTION_FAILED;
6796 szwFolder = strdupAtoW(szFolder);
6798 return ERROR_FUNCTION_FAILED;
6800 szwFolderPath = strdupAtoW(szFolderPath);
6803 HeapFree(GetProcessHeap(),0,szwFolder);
6804 return ERROR_FUNCTION_FAILED;
6807 rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
6809 HeapFree(GetProcessHeap(),0,szwFolder);
6810 HeapFree(GetProcessHeap(),0,szwFolderPath);
6815 UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
6816 LPCWSTR szFolderPath)
6820 LPWSTR path2 = NULL;
6823 TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
6826 return ERROR_INVALID_HANDLE;
6828 if (szFolderPath[0]==0)
6829 return ERROR_FUNCTION_FAILED;
6831 if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)
6832 return ERROR_FUNCTION_FAILED;
6834 path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);
6837 return ERROR_INVALID_PARAMETER;
6839 HeapFree(GetProcessHeap(),0,folder->Property);
6840 folder->Property = build_directory_name(2, szFolderPath, NULL);
6842 if (lstrcmpiW(path, folder->Property) == 0)
6845 * Resolved Target has not really changed, so just
6846 * set this folder and do not recalculate everything.
6848 HeapFree(GetProcessHeap(),0,folder->ResolvedTarget);
6849 folder->ResolvedTarget = NULL;
6850 path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL);
6851 HeapFree(GetProcessHeap(),0,path2);
6855 for (i = 0; i < package->loaded_folders; i++)
6857 HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
6858 package->folders[i].ResolvedTarget=NULL;
6861 for (i = 0; i < package->loaded_folders; i++)
6863 path2=resolve_folder(package, package->folders[i].Directory, FALSE,
6865 HeapFree(GetProcessHeap(),0,path2);
6868 HeapFree(GetProcessHeap(),0,path);
6870 return ERROR_SUCCESS;
6873 /***********************************************************************
6874 * MsiSetTargetPathW (MSI.@)
6876 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
6877 LPCWSTR szFolderPath)
6879 MSIPACKAGE *package;
6882 TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
6884 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
6885 ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
6886 msiobj_release( &package->hdr );
6890 /***********************************************************************
6891 * MsiGetMode (MSI.@)
6893 * Returns an internal installer state (if it is running in a mode iRunMode)
6896 * hInstall [I] Handle to the installation
6897 * hRunMode [I] Checking run mode
6898 * MSIRUNMODE_ADMIN Administrative mode
6899 * MSIRUNMODE_ADVERTISE Advertisement mode
6900 * MSIRUNMODE_MAINTENANCE Maintenance mode
6901 * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled
6902 * MSIRUNMODE_LOGENABLED Log file is writing
6903 * MSIRUNMODE_OPERATIONS Operations in progress??
6904 * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed
6905 * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation
6906 * MSIRUNMODE_CABINET Files from cabinet are installed
6907 * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is suppressed
6908 * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is suppressed
6909 * MSIRUNMODE_RESERVED11 Reserved
6910 * MSIRUNMODE_WINDOWS9X Running under Windows95/98
6911 * MSIRUNMODE_ZAWENABLED Demand installation is supported
6912 * MSIRUNMODE_RESERVED14 Reserved
6913 * MSIRUNMODE_RESERVED15 Reserved
6914 * MSIRUNMODE_SCHEDULED called from install script
6915 * MSIRUNMODE_ROLLBACK called from rollback script
6916 * MSIRUNMODE_COMMIT called from commit script
6919 * In the state: TRUE
6920 * Not in the state: FALSE
6924 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
6926 FIXME("STUB (iRunMode=%i)\n",iRunMode);
6930 /***********************************************************************
6931 * MsiSetFeatureStateA (MSI.@)
6933 * According to the docs, when this is called it immediately recalculates
6934 * all the component states as well
6936 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
6937 INSTALLSTATE iState)
6939 LPWSTR szwFeature = NULL;
6942 szwFeature = strdupAtoW(szFeature);
6945 return ERROR_FUNCTION_FAILED;
6947 rc = MsiSetFeatureStateW(hInstall,szwFeature, iState);
6949 HeapFree(GetProcessHeap(),0,szwFeature);
6956 UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
6957 INSTALLSTATE iState)
6960 UINT rc = ERROR_SUCCESS;
6962 TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
6964 index = get_loaded_feature(package,szFeature);
6966 return ERROR_UNKNOWN_FEATURE;
6968 package->features[index].ActionRequest= iState;
6969 package->features[index].Action= iState;
6971 ACTION_UpdateComponentStates(package,szFeature);
6973 /* update all the features that are children of this feature */
6974 for (i = 0; i < package->loaded_features; i++)
6976 if (strcmpW(szFeature, package->features[i].Feature_Parent) == 0)
6977 MSI_SetFeatureStateW(package, package->features[i].Feature, iState);
6983 /***********************************************************************
6984 * MsiSetFeatureStateW (MSI.@)
6986 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
6987 INSTALLSTATE iState)
6989 MSIPACKAGE* package;
6990 UINT rc = ERROR_SUCCESS;
6992 TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
6994 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
6996 return ERROR_INVALID_HANDLE;
6998 rc = MSI_SetFeatureStateW(package,szFeature,iState);
7000 msiobj_release( &package->hdr );
7004 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
7005 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7007 LPWSTR szwFeature = NULL;
7010 szwFeature = strdupAtoW(szFeature);
7012 rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
7014 HeapFree( GetProcessHeap(), 0 , szwFeature);
7019 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
7020 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7024 index = get_loaded_feature(package,szFeature);
7026 return ERROR_UNKNOWN_FEATURE;
7029 *piInstalled = package->features[index].Installed;
7032 *piAction = package->features[index].Action;
7034 TRACE("returning %i %i\n",*piInstalled,*piAction);
7036 return ERROR_SUCCESS;
7039 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
7040 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7042 MSIPACKAGE* package;
7045 TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
7048 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7050 return ERROR_INVALID_HANDLE;
7051 ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
7052 msiobj_release( &package->hdr );
7056 /***********************************************************************
7057 * MsiGetComponentStateA (MSI.@)
7059 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
7060 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7062 LPWSTR szwComponent= NULL;
7065 szwComponent= strdupAtoW(szComponent);
7067 rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
7069 HeapFree( GetProcessHeap(), 0 , szwComponent);
7074 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
7075 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7079 TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
7082 index = get_loaded_component(package,szComponent);
7084 return ERROR_UNKNOWN_COMPONENT;
7087 *piInstalled = package->components[index].Installed;
7090 *piAction = package->components[index].Action;
7092 TRACE("states (%i, %i)\n",
7093 (piInstalled)?*piInstalled:-1,(piAction)?*piAction:-1);
7095 return ERROR_SUCCESS;
7098 /***********************************************************************
7099 * MsiGetComponentStateW (MSI.@)
7101 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
7102 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7104 MSIPACKAGE* package;
7107 TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
7108 piInstalled, piAction);
7110 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7112 return ERROR_INVALID_HANDLE;
7113 ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
7114 msiobj_release( &package->hdr );
7119 static UINT ACTION_Template(MSIPACKAGE *package)
7123 MSIRECORD * row = 0;
7124 static const WCHAR ExecSeqQuery[] = {0};
7126 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
7127 if (rc != ERROR_SUCCESS)
7130 rc = MSI_ViewExecute(view, 0);
7131 if (rc != ERROR_SUCCESS)
7133 MSI_ViewClose(view);
7134 msiobj_release(&view->hdr);
7140 rc = MSI_ViewFetch(view,&row);
7141 if (rc != ERROR_SUCCESS)
7147 msiobj_release(&row->hdr);
7149 MSI_ViewClose(view);
7150 msiobj_release(&view->hdr);