Use the new registry functions in registry.c.
[wine/wine-gecko.git] / dlls / msi / action.c
blobade6b88578f23754c15027d8937feed1f204bd80
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Pages I need
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
29 #include <stdarg.h>
30 #include <stdio.h>
32 #define COBJMACROS
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winreg.h"
38 #include "wine/debug.h"
39 #include "fdi.h"
40 #include "msi.h"
41 #include "msiquery.h"
42 #include "msvcrt/fcntl.h"
43 #include "objbase.h"
44 #include "objidl.h"
45 #include "msipriv.h"
46 #include "winnls.h"
47 #include "winuser.h"
48 #include "shlobj.h"
49 #include "wine/unicode.h"
50 #include "ver.h"
52 #define CUSTOM_ACTION_TYPE_MASK 0x3F
53 #define REG_PROGRESS_VALUE 13200
54 #define COMPONENT_PROGRESS_VALUE 24000
56 WINE_DEFAULT_DEBUG_CHANNEL(msi);
58 typedef struct tagMSIFEATURE
60 WCHAR Feature[96];
61 WCHAR Feature_Parent[96];
62 WCHAR Title[0x100];
63 WCHAR Description[0x100];
64 INT Display;
65 INT Level;
66 WCHAR Directory[96];
67 INT Attributes;
69 INSTALLSTATE Installed;
70 INSTALLSTATE ActionRequest;
71 INSTALLSTATE Action;
73 INT ComponentCount;
74 INT Components[1024]; /* yes hardcoded limit.... I am bad */
75 INT Cost;
76 } MSIFEATURE;
78 typedef struct tagMSICOMPONENT
80 WCHAR Component[96];
81 WCHAR ComponentId[96];
82 WCHAR Directory[96];
83 INT Attributes;
84 WCHAR Condition[0x100];
85 WCHAR KeyPath[96];
87 INSTALLSTATE Installed;
88 INSTALLSTATE ActionRequest;
89 INSTALLSTATE Action;
91 BOOL Enabled;
92 INT Cost;
93 } MSICOMPONENT;
95 typedef struct tagMSIFOLDER
97 LPWSTR Directory;
98 LPWSTR TargetDefault;
99 LPWSTR SourceDefault;
101 LPWSTR ResolvedTarget;
102 LPWSTR ResolvedSource;
103 LPWSTR Property; /* initially set property */
104 INT ParentIndex;
105 INT State;
106 /* 0 = uninitialized */
107 /* 1 = existing */
108 /* 2 = created remove if empty */
109 /* 3 = created persist if empty */
110 INT Cost;
111 INT Space;
112 }MSIFOLDER;
114 typedef struct tagMSIFILE
116 LPWSTR File;
117 INT ComponentIndex;
118 LPWSTR FileName;
119 INT FileSize;
120 LPWSTR Version;
121 LPWSTR Language;
122 INT Attributes;
123 INT Sequence;
125 INT State;
126 /* 0 = uninitialize */
127 /* 1 = not present */
128 /* 2 = present but replace */
129 /* 3 = present do not replace */
130 /* 4 = Installed */
131 LPWSTR SourcePath;
132 LPWSTR TargetPath;
133 BOOL Temporary;
134 }MSIFILE;
137 * Prototypes
139 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
140 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
142 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq);
143 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action);
145 static UINT ACTION_LaunchConditions(MSIPACKAGE *package);
146 static UINT ACTION_CostInitialize(MSIPACKAGE *package);
147 static UINT ACTION_CreateFolders(MSIPACKAGE *package);
148 static UINT ACTION_CostFinalize(MSIPACKAGE *package);
149 static UINT ACTION_FileCost(MSIPACKAGE *package);
150 static UINT ACTION_InstallFiles(MSIPACKAGE *package);
151 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
152 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package);
153 static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action,
154 BOOL execute);
155 static UINT ACTION_InstallInitialize(MSIPACKAGE *package);
156 static UINT ACTION_InstallValidate(MSIPACKAGE *package);
157 static UINT ACTION_ProcessComponents(MSIPACKAGE *package);
158 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package);
159 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
160 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
161 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package);
162 static UINT ACTION_PublishProduct(MSIPACKAGE *package);
163 static UINT ACTION_WriteIniValues(MSIPACKAGE *package);
164 static UINT ACTION_SelfRegModules(MSIPACKAGE *package);
165 static UINT ACTION_PublishFeatures(MSIPACKAGE *package);
166 static UINT ACTION_RegisterProduct(MSIPACKAGE *package);
167 static UINT ACTION_InstallExecute(MSIPACKAGE *package);
168 static UINT ACTION_InstallFinalize(MSIPACKAGE *package);
169 static UINT ACTION_ForceReboot(MSIPACKAGE *package);
171 static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source,
172 const LPWSTR target, const INT type);
173 static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source,
174 const LPWSTR target, const INT type);
175 static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source,
176 const LPWSTR target, const INT type);
177 static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source,
178 const LPWSTR target, const INT type);
179 static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source,
180 const LPWSTR target, const INT type);
182 static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data);
183 static LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name,
184 BOOL source, BOOL set_prop, MSIFOLDER **folder);
185 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name,
186 LPWSTR *FilePath);
187 static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path);
190 * consts and values used
192 static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
193 static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
194 static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
195 static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
196 static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
197 static const WCHAR c_collen[] = {'C',':','\\',0};
199 static const WCHAR cszlsb[]={'[',0};
200 static const WCHAR cszrsb[]={']',0};
201 static const WCHAR cszbs[]={'\\',0};
203 const static WCHAR szCreateFolders[] =
204 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
205 const static WCHAR szCostFinalize[] =
206 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
207 const static WCHAR szInstallFiles[] =
208 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
209 const static WCHAR szDuplicateFiles[] =
210 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
211 const static WCHAR szWriteRegistryValues[] =
212 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
213 const static WCHAR szCostInitialize[] =
214 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
215 const static WCHAR szFileCost[] = {'F','i','l','e','C','o','s','t',0};
216 const static WCHAR szInstallInitialize[] =
217 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
218 const static WCHAR szInstallValidate[] =
219 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
220 const static WCHAR szLaunchConditions[] =
221 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
222 const static WCHAR szProcessComponents[] =
223 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
224 const static WCHAR szRegisterTypeLibraries[] =
225 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r',
226 'i','e','s',0};
227 const static WCHAR szRegisterClassInfo[] =
228 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
229 const static WCHAR szRegisterProgIdInfo[] =
230 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
231 const static WCHAR szCreateShortcuts[] =
232 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
233 const static WCHAR szPublishProduct[] =
234 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
235 const static WCHAR szWriteIniValues[] =
236 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
237 const static WCHAR szSelfRegModules[] =
238 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
239 const static WCHAR szPublishFeatures[] =
240 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
241 const static WCHAR szRegisterProduct[] =
242 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
243 const static WCHAR szInstallExecute[] =
244 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
245 const static WCHAR szInstallExecuteAgain[] =
246 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
247 const static WCHAR szInstallFinalize[] =
248 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
249 const static WCHAR szForceReboot[] =
250 {'F','o','r','c','e','R','e','b','o','o','t',0};
252 /********************************************************
253 * helper functions to get around current HACKS and such
254 ********************************************************/
255 inline static void reduce_to_longfilename(WCHAR* filename)
257 LPWSTR p = strchrW(filename,'|');
258 if (p)
259 memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR));
262 inline static char *strdupWtoA( const WCHAR *str )
264 char *ret = NULL;
265 if (str)
267 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL
269 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
270 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
272 return ret;
275 inline static WCHAR *strdupAtoW( const char *str )
277 WCHAR *ret = NULL;
278 if (str)
280 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
281 if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
282 MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
284 return ret;
287 static LPWSTR dupstrW(LPCWSTR src)
289 LPWSTR dest;
290 if (!src) return NULL;
291 dest = HeapAlloc(GetProcessHeap(), 0, (strlenW(src)+1)*sizeof(WCHAR));
292 strcpyW(dest, src);
293 return dest;
296 inline static WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
298 UINT rc;
299 DWORD sz;
300 LPWSTR ret;
302 sz = 0;
303 if (MSI_RecordIsNull(row,index))
304 return NULL;
306 rc = MSI_RecordGetStringW(row,index,NULL,&sz);
308 /* having an empty string is different than NULL */
309 if (sz == 0)
311 ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR));
312 ret[0] = 0;
313 return ret;
316 sz ++;
317 ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
318 rc = MSI_RecordGetStringW(row,index,ret,&sz);
319 if (rc!=ERROR_SUCCESS)
321 ERR("Unable to load dynamic string\n");
322 HeapFree(GetProcessHeap(), 0, ret);
323 ret = NULL;
325 return ret;
328 inline static LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop,
329 UINT* rc)
331 DWORD sz = 0;
332 LPWSTR str;
333 UINT r;
335 r = MSI_GetPropertyW(package, prop, NULL, &sz);
336 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
338 if (rc)
339 *rc = r;
340 return NULL;
342 sz++;
343 str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
344 r = MSI_GetPropertyW(package, prop, str, &sz);
345 if (r != ERROR_SUCCESS)
347 HeapFree(GetProcessHeap(),0,str);
348 str = NULL;
350 if (rc)
351 *rc = r;
352 return str;
355 inline static int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
357 int rc = -1;
358 DWORD i;
360 for (i = 0; i < package->loaded_components; i++)
362 if (strcmpW(Component,package->components[i].Component)==0)
364 rc = i;
365 break;
368 return rc;
371 inline static int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
373 int rc = -1;
374 DWORD i;
376 for (i = 0; i < package->loaded_features; i++)
378 if (strcmpW(Feature,package->features[i].Feature)==0)
380 rc = i;
381 break;
384 return rc;
387 inline static int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
389 int rc = -1;
390 DWORD i;
392 for (i = 0; i < package->loaded_files; i++)
394 if (strcmpW(file,package->files[i].File)==0)
396 rc = i;
397 break;
400 return rc;
404 static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
406 DWORD i;
407 DWORD index;
409 if (!package)
410 return -2;
412 for (i=0; i < package->loaded_files; i++)
413 if (strcmpW(package->files[i].File,name)==0)
414 return -1;
416 index = package->loaded_files;
417 package->loaded_files++;
418 if (package->loaded_files== 1)
419 package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
420 else
421 package->files = HeapReAlloc(GetProcessHeap(),0,
422 package->files , package->loaded_files * sizeof(MSIFILE));
424 memset(&package->files[index],0,sizeof(MSIFILE));
426 package->files[index].File = dupstrW(name);
427 package->files[index].TargetPath = dupstrW(path);
428 package->files[index].Temporary = TRUE;
430 TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));
432 return 0;
435 void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package)
437 DWORD i;
439 if (!package)
440 return;
442 for (i = 0; i < package->loaded_files; i++)
444 if (package->files[i].Temporary)
446 TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));
447 DeleteFileW(package->files[i].TargetPath);
453 /* Called when the package is being closed */
454 extern void ACTION_free_package_structures( MSIPACKAGE* package)
456 INT i;
458 TRACE("Freeing package action data\n");
460 /* No dynamic buffers in features */
461 if (package->features && package->loaded_features > 0)
462 HeapFree(GetProcessHeap(),0,package->features);
464 for (i = 0; i < package->loaded_folders; i++)
466 HeapFree(GetProcessHeap(),0,package->folders[i].Directory);
467 HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault);
468 HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault);
469 HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
470 HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource);
471 HeapFree(GetProcessHeap(),0,package->folders[i].Property);
473 if (package->folders && package->loaded_folders > 0)
474 HeapFree(GetProcessHeap(),0,package->folders);
476 /* no dynamic buffers in components */
477 if (package->components && package->loaded_components > 0)
478 HeapFree(GetProcessHeap(),0,package->components);
480 for (i = 0; i < package->loaded_files; i++)
482 HeapFree(GetProcessHeap(),0,package->files[i].File);
483 HeapFree(GetProcessHeap(),0,package->files[i].FileName);
484 HeapFree(GetProcessHeap(),0,package->files[i].Version);
485 HeapFree(GetProcessHeap(),0,package->files[i].Language);
486 HeapFree(GetProcessHeap(),0,package->files[i].SourcePath);
487 HeapFree(GetProcessHeap(),0,package->files[i].TargetPath);
490 if (package->files && package->loaded_files > 0)
491 HeapFree(GetProcessHeap(),0,package->files);
493 for (i = 0; i < package->DeferredActionCount; i++)
494 HeapFree(GetProcessHeap(),0,package->DeferredAction[i]);
495 HeapFree(GetProcessHeap(),0,package->DeferredAction);
497 for (i = 0; i < package->CommitActionCount; i++)
498 HeapFree(GetProcessHeap(),0,package->CommitAction[i]);
499 HeapFree(GetProcessHeap(),0,package->CommitAction);
501 HeapFree(GetProcessHeap(),0,package->PackagePath);
504 static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )
506 MSIRECORD * row;
508 row = MSI_CreateRecord(4);
509 MSI_RecordSetInteger(row,1,a);
510 MSI_RecordSetInteger(row,2,b);
511 MSI_RecordSetInteger(row,3,c);
512 MSI_RecordSetInteger(row,4,d);
513 MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);
514 msiobj_release(&row->hdr);
517 static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
519 static const WCHAR Query_t[] =
520 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
521 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
522 ' ','\'','%','s','\'',0};
523 WCHAR message[1024];
524 UINT rc;
525 MSIQUERY * view;
526 MSIRECORD * row = 0;
527 LPWSTR ptr;
529 if (!package->LastAction || strcmpW(package->LastAction,action))
531 rc = MSI_OpenQuery(package->db, &view, Query_t, action);
532 if (rc != ERROR_SUCCESS)
533 return;
535 rc = MSI_ViewExecute(view, 0);
536 if (rc != ERROR_SUCCESS)
538 MSI_ViewClose(view);
539 return;
541 rc = MSI_ViewFetch(view,&row);
542 if (rc != ERROR_SUCCESS)
544 MSI_ViewClose(view);
545 return;
548 if (MSI_RecordIsNull(row,3))
550 msiobj_release(&row->hdr);
551 MSI_ViewClose(view);
552 msiobj_release(&view->hdr);
553 return;
556 /* update the cached actionformat */
557 HeapFree(GetProcessHeap(),0,package->ActionFormat);
558 package->ActionFormat = load_dynamic_stringW(row,3);
560 HeapFree(GetProcessHeap(),0,package->LastAction);
561 package->LastAction = dupstrW(action);
563 msiobj_release(&row->hdr);
564 MSI_ViewClose(view);
565 msiobj_release(&view->hdr);
568 message[0]=0;
569 ptr = package->ActionFormat;
570 while (*ptr)
572 LPWSTR ptr2;
573 LPWSTR data=NULL;
574 WCHAR tmp[1023];
575 INT field;
577 ptr2 = strchrW(ptr,'[');
578 if (ptr2)
580 strncpyW(tmp,ptr,ptr2-ptr);
581 tmp[ptr2-ptr]=0;
582 strcatW(message,tmp);
583 ptr2++;
584 field = atoiW(ptr2);
585 data = load_dynamic_stringW(record,field);
586 if (data)
588 strcatW(message,data);
589 HeapFree(GetProcessHeap(),0,data);
591 ptr=strchrW(ptr2,']');
592 ptr++;
594 else
596 strcatW(message,ptr);
597 break;
601 row = MSI_CreateRecord(1);
602 MSI_RecordSetStringW(row,1,message);
604 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
605 msiobj_release(&row->hdr);
609 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
611 static const WCHAR template_s[]=
612 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ','%','s','.',0};
613 static const WCHAR format[] =
614 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
615 static const WCHAR Query_t[] =
616 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
617 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
618 ' ','\'','%','s','\'',0};
619 WCHAR message[1024];
620 WCHAR timet[0x100];
621 UINT rc;
622 MSIQUERY * view;
623 MSIRECORD * row = 0;
624 WCHAR *ActionText=NULL;
626 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
628 rc = MSI_OpenQuery(package->db, &view, Query_t, action);
629 if (rc != ERROR_SUCCESS)
630 return;
631 rc = MSI_ViewExecute(view, 0);
632 if (rc != ERROR_SUCCESS)
634 MSI_ViewClose(view);
635 msiobj_release(&view->hdr);
636 return;
638 rc = MSI_ViewFetch(view,&row);
639 if (rc != ERROR_SUCCESS)
641 MSI_ViewClose(view);
642 msiobj_release(&view->hdr);
643 return;
646 ActionText = load_dynamic_stringW(row,2);
647 msiobj_release(&row->hdr);
648 MSI_ViewClose(view);
649 msiobj_release(&view->hdr);
651 sprintfW(message,template_s,timet,action,ActionText);
653 row = MSI_CreateRecord(1);
654 MSI_RecordSetStringW(row,1,message);
656 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
657 msiobj_release(&row->hdr);
658 HeapFree(GetProcessHeap(),0,ActionText);
661 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
662 UINT rc)
664 MSIRECORD * row;
665 static const WCHAR template_s[]=
666 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ','%','s',
667 '.',0};
668 static const WCHAR template_e[]=
669 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ','%','s',
670 '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ','%','i','.',0};
671 static const WCHAR format[] =
672 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
673 WCHAR message[1024];
674 WCHAR timet[0x100];
676 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
677 if (start)
678 sprintfW(message,template_s,timet,action);
679 else
680 sprintfW(message,template_e,timet,action,rc);
682 row = MSI_CreateRecord(1);
683 MSI_RecordSetStringW(row,1,message);
685 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
686 msiobj_release(&row->hdr);
690 * build_directory_name()
692 * This function is to save messing round with directory names
693 * It handles adding backslashes between path segments,
694 * and can add \ at the end of the directory name if told to.
696 * It takes a variable number of arguments.
697 * It always allocates a new string for the result, so make sure
698 * to free the return value when finished with it.
700 * The first arg is the number of path segments that follow.
701 * The arguments following count are a list of path segments.
702 * A path segment may be NULL.
704 * Path segments will be added with a \ separating them.
705 * A \ will not be added after the last segment, however if the
706 * last segment is NULL, then the last character will be a \
709 static LPWSTR build_directory_name(DWORD count, ...)
711 DWORD sz = 1, i;
712 LPWSTR dir;
713 va_list va;
715 va_start(va,count);
716 for(i=0; i<count; i++)
718 LPCWSTR str = va_arg(va,LPCWSTR);
719 if (str)
720 sz += strlenW(str) + 1;
722 va_end(va);
724 dir = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
725 dir[0]=0;
727 va_start(va,count);
728 for(i=0; i<count; i++)
730 LPCWSTR str = va_arg(va,LPCWSTR);
731 if (!str)
732 continue;
733 strcatW(dir, str);
734 if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\\')
735 strcatW(dir, cszbs);
737 return dir;
741 /****************************************************
742 * TOP level entry points
743 *****************************************************/
745 UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
746 LPCWSTR szCommandLine)
748 DWORD sz;
749 WCHAR buffer[10];
750 UINT rc;
751 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
752 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
753 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
755 MSI_SetPropertyW(package, szAction, szInstall);
757 if (szPackagePath)
759 LPWSTR p, check, path;
761 package->PackagePath = dupstrW(szPackagePath);
762 path = dupstrW(szPackagePath);
763 p = strrchrW(path,'\\');
764 if (p)
766 p++;
767 *p=0;
770 check = load_dynamic_property(package, cszSourceDir,NULL);
771 if (!check)
772 MSI_SetPropertyW(package, cszSourceDir, path);
773 else
774 HeapFree(GetProcessHeap(), 0, check);
776 HeapFree(GetProcessHeap(), 0, path);
779 if (szCommandLine)
781 LPWSTR ptr,ptr2;
782 ptr = (LPWSTR)szCommandLine;
784 while (*ptr)
786 WCHAR *prop = NULL;
787 WCHAR *val = NULL;
789 TRACE("Looking at %s\n",debugstr_w(ptr));
791 ptr2 = strchrW(ptr,'=');
792 if (ptr2)
794 BOOL quote=FALSE;
795 DWORD len = 0;
797 while (*ptr == ' ') ptr++;
798 len = ptr2-ptr;
799 prop = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
800 strncpyW(prop,ptr,len);
801 prop[len]=0;
802 ptr2++;
804 len = 0;
805 ptr = ptr2;
806 while (*ptr && (quote || (!quote && *ptr!=' ')))
808 if (*ptr == '"')
809 quote = !quote;
810 ptr++;
811 len++;
814 if (*ptr2=='"')
816 ptr2++;
817 len -= 2;
819 val = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
820 strncpyW(val,ptr2,len);
821 val[len] = 0;
823 if (strlenW(prop) > 0)
825 TRACE("Found commandline property (%s) = (%s)\n",
826 debugstr_w(prop), debugstr_w(val));
827 MSI_SetPropertyW(package,prop,val);
829 HeapFree(GetProcessHeap(),0,val);
830 HeapFree(GetProcessHeap(),0,prop);
832 ptr++;
836 sz = 10;
837 if (MSI_GetPropertyW(package,szUILevel,buffer,&sz) == ERROR_SUCCESS)
839 if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED)
841 rc = ACTION_ProcessUISequence(package);
842 if (rc == ERROR_SUCCESS)
843 rc = ACTION_ProcessExecSequence(package,TRUE);
845 else
846 rc = ACTION_ProcessExecSequence(package,FALSE);
848 else
849 rc = ACTION_ProcessExecSequence(package,FALSE);
851 /* process the ending type action */
852 if (rc == ERROR_SUCCESS)
853 rc = ACTION_PerformActionSequence(package,-1);
854 else if (rc == ERROR_FUNCTION_FAILED)
855 rc = ACTION_PerformActionSequence(package,-3);
857 return rc;
860 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
862 MSIQUERY * view;
863 UINT rc;
864 WCHAR buffer[0x100];
865 DWORD sz = 0x100;
866 MSIRECORD * row = 0;
867 static const WCHAR ExecSeqQuery[] = {
868 's','e','l','e','c','t',' ','*',' ',
869 'f','r','o','m',' ',
870 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
871 'S','e','q','u','e','n','c','e',' ',
872 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
873 '=',' ','%','i',0};
875 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
877 if (rc == ERROR_SUCCESS)
879 rc = MSI_ViewExecute(view, 0);
881 if (rc != ERROR_SUCCESS)
883 MSI_ViewClose(view);
884 msiobj_release(&view->hdr);
885 goto end;
888 TRACE("Running the actions\n");
890 rc = MSI_ViewFetch(view,&row);
891 if (rc != ERROR_SUCCESS)
893 rc = ERROR_SUCCESS;
894 goto end;
897 /* check conditions */
898 if (!MSI_RecordIsNull(row,2))
900 LPWSTR cond = NULL;
901 cond = load_dynamic_stringW(row,2);
903 if (cond)
905 /* this is a hack to skip errors in the condition code */
906 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
908 HeapFree(GetProcessHeap(),0,cond);
909 msiobj_release(&row->hdr);
910 goto end;
912 else
913 HeapFree(GetProcessHeap(),0,cond);
917 sz=0x100;
918 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
919 if (rc != ERROR_SUCCESS)
921 ERR("Error is %x\n",rc);
922 msiobj_release(&row->hdr);
923 goto end;
926 rc = ACTION_PerformAction(package,buffer);
927 msiobj_release(&row->hdr);
928 end:
929 MSI_ViewClose(view);
930 msiobj_release(&view->hdr);
932 else
933 rc = ERROR_SUCCESS;
935 return rc;
938 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
940 MSIQUERY * view;
941 UINT rc;
942 static const WCHAR ExecSeqQuery[] = {
943 's','e','l','e','c','t',' ','*',' ',
944 'f','r','o','m',' ',
945 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
946 'S','e','q','u','e','n','c','e',' ',
947 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
948 '>',' ','%','i',' ','o','r','d','e','r',' ',
949 'b','y',' ','S','e','q','u','e','n','c','e',0 };
950 MSIRECORD * row = 0;
951 static const WCHAR IVQuery[] = {
952 's','e','l','e','c','t',' ','S','e','q','u','e','n','c','e',' ',
953 'f','r','o','m',' ','I','n','s','t','a','l','l',
954 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e',' ',
955 'w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',' ',
956 '`','I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`',
958 INT seq = 0;
960 /* get the sequence number */
961 if (UIran)
963 rc = MSI_DatabaseOpenViewW(package->db, IVQuery, &view);
964 if (rc != ERROR_SUCCESS)
965 return rc;
966 rc = MSI_ViewExecute(view, 0);
967 if (rc != ERROR_SUCCESS)
969 MSI_ViewClose(view);
970 msiobj_release(&view->hdr);
971 return rc;
973 rc = MSI_ViewFetch(view,&row);
974 if (rc != ERROR_SUCCESS)
976 MSI_ViewClose(view);
977 msiobj_release(&view->hdr);
978 return rc;
980 seq = MSI_RecordGetInteger(row,1);
981 msiobj_release(&row->hdr);
982 MSI_ViewClose(view);
983 msiobj_release(&view->hdr);
986 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
987 if (rc == ERROR_SUCCESS)
989 rc = MSI_ViewExecute(view, 0);
991 if (rc != ERROR_SUCCESS)
993 MSI_ViewClose(view);
994 msiobj_release(&view->hdr);
995 goto end;
998 TRACE("Running the actions\n");
1000 while (1)
1002 WCHAR buffer[0x100];
1003 DWORD sz = 0x100;
1005 rc = MSI_ViewFetch(view,&row);
1006 if (rc != ERROR_SUCCESS)
1008 rc = ERROR_SUCCESS;
1009 break;
1012 /* check conditions */
1013 if (!MSI_RecordIsNull(row,2))
1015 LPWSTR cond = NULL;
1016 cond = load_dynamic_stringW(row,2);
1018 if (cond)
1020 /* this is a hack to skip errors in the condition code */
1021 if (MSI_EvaluateConditionW(package, cond) ==
1022 MSICONDITION_FALSE)
1024 HeapFree(GetProcessHeap(),0,cond);
1025 msiobj_release(&row->hdr);
1026 continue;
1028 else
1029 HeapFree(GetProcessHeap(),0,cond);
1033 sz=0x100;
1034 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
1035 if (rc != ERROR_SUCCESS)
1037 ERR("Error is %x\n",rc);
1038 msiobj_release(&row->hdr);
1039 break;
1042 rc = ACTION_PerformAction(package,buffer);
1044 if (rc == ERROR_FUNCTION_NOT_CALLED)
1045 rc = ERROR_SUCCESS;
1047 if (rc != ERROR_SUCCESS)
1049 ERR("Execution halted due to error (%i)\n",rc);
1050 msiobj_release(&row->hdr);
1051 break;
1054 msiobj_release(&row->hdr);
1057 MSI_ViewClose(view);
1058 msiobj_release(&view->hdr);
1061 end:
1062 return rc;
1066 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1068 MSIQUERY * view;
1069 UINT rc;
1070 static const WCHAR ExecSeqQuery [] = {
1071 's','e','l','e','c','t',' ','*',' ',
1072 'f','r','o','m',' ','I','n','s','t','a','l','l',
1073 'U','I','S','e','q','u','e','n','c','e',' ',
1074 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', '>',' ','0',' ',
1075 'o','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e',0};
1077 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1079 if (rc == ERROR_SUCCESS)
1081 rc = MSI_ViewExecute(view, 0);
1083 if (rc != ERROR_SUCCESS)
1085 MSI_ViewClose(view);
1086 msiobj_release(&view->hdr);
1087 goto end;
1090 TRACE("Running the actions \n");
1092 while (1)
1094 WCHAR buffer[0x100];
1095 DWORD sz = 0x100;
1096 MSIRECORD * row = 0;
1098 rc = MSI_ViewFetch(view,&row);
1099 if (rc != ERROR_SUCCESS)
1101 rc = ERROR_SUCCESS;
1102 break;
1105 /* check conditions */
1106 if (!MSI_RecordIsNull(row,2))
1108 LPWSTR cond = NULL;
1109 cond = load_dynamic_stringW(row,2);
1111 if (cond)
1113 /* this is a hack to skip errors in the condition code */
1114 if (MSI_EvaluateConditionW(package, cond) ==
1115 MSICONDITION_FALSE)
1117 HeapFree(GetProcessHeap(),0,cond);
1118 msiobj_release(&row->hdr);
1119 continue;
1121 else
1122 HeapFree(GetProcessHeap(),0,cond);
1126 sz=0x100;
1127 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
1128 if (rc != ERROR_SUCCESS)
1130 ERR("Error is %x\n",rc);
1131 msiobj_release(&row->hdr);
1132 break;
1135 rc = ACTION_PerformAction(package,buffer);
1137 if (rc == ERROR_FUNCTION_NOT_CALLED)
1138 rc = ERROR_SUCCESS;
1140 if (rc != ERROR_SUCCESS)
1142 ERR("Execution halted due to error (%i)\n",rc);
1143 msiobj_release(&row->hdr);
1144 break;
1147 msiobj_release(&row->hdr);
1150 MSI_ViewClose(view);
1151 msiobj_release(&view->hdr);
1154 end:
1155 return rc;
1158 /********************************************************
1159 * ACTION helper functions and functions that perform the actions
1160 *******************************************************/
1163 * Alot of actions are really important even if they don't do anything
1164 * explicit.. Lots of properties are set at the beginning of the installation
1165 * CostFinalize does a bunch of work to translated the directories and such
1167 * But until I get write access to the database that is hard, so I am going to
1168 * hack it to see if I can get something to run.
1170 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action)
1172 UINT rc = ERROR_SUCCESS;
1174 TRACE("Performing action (%s)\n",debugstr_w(action));
1175 ui_actioninfo(package, action, TRUE, 0);
1176 ui_actionstart(package, action);
1178 /* pre install, setup and configuration block */
1179 if (strcmpW(action,szLaunchConditions)==0)
1180 rc = ACTION_LaunchConditions(package);
1181 else if (strcmpW(action,szCostInitialize)==0)
1182 rc = ACTION_CostInitialize(package);
1183 else if (strcmpW(action,szFileCost)==0)
1184 rc = ACTION_FileCost(package);
1185 else if (strcmpW(action,szCostFinalize)==0)
1186 rc = ACTION_CostFinalize(package);
1187 else if (strcmpW(action,szInstallValidate)==0)
1188 rc = ACTION_InstallValidate(package);
1190 /* install block */
1191 else if (strcmpW(action,szProcessComponents)==0)
1192 rc = ACTION_ProcessComponents(package);
1193 else if (strcmpW(action,szInstallInitialize)==0)
1194 rc = ACTION_InstallInitialize(package);
1195 else if (strcmpW(action,szCreateFolders)==0)
1196 rc = ACTION_CreateFolders(package);
1197 else if (strcmpW(action,szInstallFiles)==0)
1198 rc = ACTION_InstallFiles(package);
1199 else if (strcmpW(action,szDuplicateFiles)==0)
1200 rc = ACTION_DuplicateFiles(package);
1201 else if (strcmpW(action,szWriteRegistryValues)==0)
1202 rc = ACTION_WriteRegistryValues(package);
1203 else if (strcmpW(action,szRegisterTypeLibraries)==0)
1204 rc = ACTION_RegisterTypeLibraries(package);
1205 else if (strcmpW(action,szRegisterClassInfo)==0)
1206 rc = ACTION_RegisterClassInfo(package);
1207 else if (strcmpW(action,szRegisterProgIdInfo)==0)
1208 rc = ACTION_RegisterProgIdInfo(package);
1209 else if (strcmpW(action,szCreateShortcuts)==0)
1210 rc = ACTION_CreateShortcuts(package);
1211 else if (strcmpW(action,szPublishProduct)==0)
1212 rc = ACTION_PublishProduct(package);
1213 else if (strcmpW(action,szWriteIniValues)==0)
1214 rc = ACTION_WriteIniValues(package);
1215 else if (strcmpW(action,szSelfRegModules)==0)
1216 rc = ACTION_SelfRegModules(package);
1217 else if (strcmpW(action,szPublishFeatures)==0)
1218 rc = ACTION_PublishFeatures(package);
1219 else if (strcmpW(action,szRegisterProduct)==0)
1220 rc = ACTION_RegisterProduct(package);
1221 else if (strcmpW(action,szInstallExecute)==0)
1222 rc = ACTION_InstallExecute(package);
1223 else if (strcmpW(action,szInstallExecuteAgain)==0)
1224 rc = ACTION_InstallExecute(package);
1225 else if (strcmpW(action,szInstallFinalize)==0)
1226 rc = ACTION_InstallFinalize(package);
1227 else if (strcmpW(action,szForceReboot)==0)
1228 rc = ACTION_ForceReboot(package);
1231 Called during iTunes but unimplemented and seem important
1233 ResolveSource (sets SourceDir)
1235 else if ((rc = ACTION_CustomAction(package,action,FALSE)) != ERROR_SUCCESS)
1237 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
1238 rc = ERROR_FUNCTION_NOT_CALLED;
1241 ui_actioninfo(package, action, FALSE, rc);
1242 return rc;
1246 static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action,
1247 BOOL execute)
1249 UINT rc = ERROR_SUCCESS;
1250 MSIQUERY * view;
1251 MSIRECORD * row = 0;
1252 static const WCHAR ExecSeqQuery[] =
1253 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','C','u','s','t','o'
1254 ,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i'
1255 ,'o','n','`',' ','=',' ','`','%','s','`',0};
1256 UINT type;
1257 LPWSTR source;
1258 LPWSTR target;
1259 WCHAR *deformated=NULL;
1261 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, action);
1262 if (rc != ERROR_SUCCESS)
1263 return rc;
1265 rc = MSI_ViewExecute(view, 0);
1266 if (rc != ERROR_SUCCESS)
1268 MSI_ViewClose(view);
1269 msiobj_release(&view->hdr);
1270 return rc;
1273 rc = MSI_ViewFetch(view,&row);
1274 if (rc != ERROR_SUCCESS)
1276 MSI_ViewClose(view);
1277 msiobj_release(&view->hdr);
1278 return rc;
1281 type = MSI_RecordGetInteger(row,2);
1283 source = load_dynamic_stringW(row,3);
1284 target = load_dynamic_stringW(row,4);
1286 TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type,
1287 debugstr_w(source), debugstr_w(target));
1289 /* handle some of the deferred actions */
1290 if (type & 0x400)
1292 if (type & 0x100)
1294 FIXME("Rollback only action... rollbacks not supported yet\n");
1295 HeapFree(GetProcessHeap(),0,source);
1296 HeapFree(GetProcessHeap(),0,target);
1297 msiobj_release(&row->hdr);
1298 MSI_ViewClose(view);
1299 msiobj_release(&view->hdr);
1300 return ERROR_SUCCESS;
1302 if (!execute)
1304 LPWSTR *newbuf = NULL;
1305 INT count;
1306 if (type & 0x200)
1308 TRACE("Deferring Commit Action!\n");
1309 count = package->CommitActionCount;
1310 package->CommitActionCount++;
1311 if (count != 0)
1312 newbuf = HeapReAlloc(GetProcessHeap(),0,
1313 package->CommitAction,
1314 package->CommitActionCount * sizeof(LPWSTR));
1315 else
1316 newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
1318 newbuf[count] = dupstrW(action);
1319 package->CommitAction = newbuf;
1321 else
1323 TRACE("Deferring Action!\n");
1324 count = package->DeferredActionCount;
1325 package->DeferredActionCount++;
1326 if (count != 0)
1327 newbuf = HeapReAlloc(GetProcessHeap(),0,
1328 package->DeferredAction,
1329 package->DeferredActionCount * sizeof(LPWSTR));
1330 else
1331 newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
1333 newbuf[count] = dupstrW(action);
1334 package->DeferredAction = newbuf;
1337 HeapFree(GetProcessHeap(),0,source);
1338 HeapFree(GetProcessHeap(),0,target);
1339 msiobj_release(&row->hdr);
1340 MSI_ViewClose(view);
1341 msiobj_release(&view->hdr);
1342 return ERROR_SUCCESS;
1344 else
1346 /*Set ActionData*/
1348 static const WCHAR szActionData[] = {
1349 'C','u','s','t','o','m','A','c','t','i','o','n','D','a','t','a',0};
1350 LPWSTR actiondata = load_dynamic_property(package,action,NULL);
1351 if (actiondata)
1352 MSI_SetPropertyW(package,szActionData,actiondata);
1354 /* dont allow asyncronous actions on forces. This is not
1355 * fully correct as some exes can run after install finishes */
1356 type &= ~0xc0;
1360 /* we are ignoring ALOT of flags and important synchronization stuff */
1361 switch (type & CUSTOM_ACTION_TYPE_MASK)
1363 case 1: /* DLL file stored in a Binary table stream */
1364 rc = HANDLE_CustomType1(package,source,target,type);
1365 break;
1366 case 2: /* EXE file stored in a Binary table strem */
1367 rc = HANDLE_CustomType2(package,source,target,type);
1368 break;
1369 case 18: /*EXE file installed with package */
1370 rc = HANDLE_CustomType18(package,source,target,type);
1371 break;
1372 case 50: /*EXE file specified by a property value */
1373 rc = HANDLE_CustomType50(package,source,target,type);
1374 break;
1375 case 34: /*EXE to be run in specified directory */
1376 rc = HANDLE_CustomType34(package,source,target,type);
1377 break;
1378 case 35: /* Directory set with formatted text. */
1379 deformat_string(package,target,&deformated);
1380 MSI_SetTargetPathW(package, source, deformated);
1381 HeapFree(GetProcessHeap(),0,deformated);
1382 break;
1383 case 51: /* Property set with formatted text. */
1384 deformat_string(package,target,&deformated);
1385 rc = MSI_SetPropertyW(package,source,deformated);
1386 HeapFree(GetProcessHeap(),0,deformated);
1387 break;
1388 default:
1389 FIXME("UNHANDLED ACTION TYPE %i (%s %s)\n",
1390 type & CUSTOM_ACTION_TYPE_MASK, debugstr_w(source),
1391 debugstr_w(target));
1394 HeapFree(GetProcessHeap(),0,source);
1395 HeapFree(GetProcessHeap(),0,target);
1396 msiobj_release(&row->hdr);
1397 MSI_ViewClose(view);
1398 msiobj_release(&view->hdr);
1399 return rc;
1402 static UINT store_binary_to_temp(MSIPACKAGE *package, const LPWSTR source,
1403 LPWSTR tmp_file)
1405 DWORD sz=MAX_PATH;
1407 if (MSI_GetPropertyW(package, cszTempFolder, tmp_file, &sz)
1408 != ERROR_SUCCESS)
1409 GetTempPathW(MAX_PATH,tmp_file);
1411 strcatW(tmp_file,source);
1413 if (GetFileAttributesW(tmp_file) != INVALID_FILE_ATTRIBUTES)
1415 TRACE("File already exists\n");
1416 return ERROR_SUCCESS;
1418 else
1420 /* write out the file */
1421 UINT rc;
1422 MSIQUERY * view;
1423 MSIRECORD * row = 0;
1424 static const WCHAR fmt[] =
1425 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','B','i'
1426 ,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`','%','s','`',0};
1427 HANDLE the_file;
1428 CHAR buffer[1024];
1430 if (track_tempfile(package, source, tmp_file)!=0)
1431 FIXME("File Name in temp tracking collision\n");
1433 the_file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
1434 FILE_ATTRIBUTE_NORMAL, NULL);
1436 if (the_file == INVALID_HANDLE_VALUE)
1437 return ERROR_FUNCTION_FAILED;
1439 rc = MSI_OpenQuery(package->db, &view, fmt, source);
1440 if (rc != ERROR_SUCCESS)
1441 return rc;
1443 rc = MSI_ViewExecute(view, 0);
1444 if (rc != ERROR_SUCCESS)
1446 MSI_ViewClose(view);
1447 msiobj_release(&view->hdr);
1448 return rc;
1451 rc = MSI_ViewFetch(view,&row);
1452 if (rc != ERROR_SUCCESS)
1454 MSI_ViewClose(view);
1455 msiobj_release(&view->hdr);
1456 return rc;
1461 DWORD write;
1462 sz = 1024;
1463 rc = MSI_RecordReadStream(row,2,buffer,&sz);
1464 if (rc != ERROR_SUCCESS)
1466 ERR("Failed to get stream\n");
1467 CloseHandle(the_file);
1468 DeleteFileW(tmp_file);
1469 break;
1471 WriteFile(the_file,buffer,sz,&write,NULL);
1472 } while (sz == 1024);
1474 CloseHandle(the_file);
1476 msiobj_release(&row->hdr);
1477 MSI_ViewClose(view);
1478 msiobj_release(&view->hdr);
1481 return ERROR_SUCCESS;
1484 typedef UINT __stdcall CustomEntry(MSIHANDLE);
1486 typedef struct
1488 MSIPACKAGE *package;
1489 WCHAR *target;
1490 WCHAR *source;
1491 } thread_struct;
1493 static DWORD WINAPI ACTION_CallDllFunction(thread_struct *stuff)
1495 HANDLE hModule;
1496 LPSTR proc;
1497 CustomEntry *fn;
1499 TRACE("calling function (%s, %s) \n", debugstr_w(stuff->source),
1500 debugstr_w(stuff->target));
1502 hModule = LoadLibraryW(stuff->source);
1503 if (hModule)
1505 proc = strdupWtoA( stuff->target );
1506 fn = (CustomEntry*)GetProcAddress(hModule,proc);
1507 if (fn)
1509 MSIHANDLE hPackage;
1510 MSIPACKAGE *package = stuff->package;
1512 TRACE("Calling function %s\n", proc);
1513 hPackage = msiobj_findhandle( &package->hdr );
1514 if (hPackage )
1516 fn(hPackage);
1517 msiobj_release( &package->hdr );
1519 else
1520 ERR("Handle for object %p not found\n", package );
1522 else
1523 ERR("Cannot load functon\n");
1525 HeapFree(GetProcessHeap(),0,proc);
1526 FreeLibrary(hModule);
1528 else
1529 ERR("Unable to load library\n");
1530 msiobj_release( &stuff->package->hdr );
1531 HeapFree(GetProcessHeap(),0,stuff->source);
1532 HeapFree(GetProcessHeap(),0,stuff->target);
1533 HeapFree(GetProcessHeap(), 0, stuff);
1534 return 0;
1537 static DWORD WINAPI DllThread(LPVOID info)
1539 thread_struct *stuff;
1540 DWORD rc = 0;
1542 TRACE("MSI Thread (0x%lx) started for custom action\n",
1543 GetCurrentThreadId());
1545 stuff = (thread_struct*)info;
1546 rc = ACTION_CallDllFunction(stuff);
1548 TRACE("MSI Thread (0x%lx) finished\n",GetCurrentThreadId());
1549 /* clse all handles for this thread */
1550 MsiCloseAllHandles();
1551 return rc;
1554 static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source,
1555 const LPWSTR target, const INT type)
1557 WCHAR tmp_file[MAX_PATH];
1558 thread_struct *info;
1559 DWORD ThreadId;
1560 HANDLE ThreadHandle;
1562 store_binary_to_temp(package, source, tmp_file);
1564 TRACE("Calling function %s from %s\n",debugstr_w(target),
1565 debugstr_w(tmp_file));
1567 if (!strchrW(tmp_file,'.'))
1569 static const WCHAR dot[]={'.',0};
1570 strcatW(tmp_file,dot);
1573 info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) );
1574 msiobj_addref( &package->hdr );
1575 info->package = package;
1576 info->target = dupstrW(target);
1577 info->source = dupstrW(tmp_file);
1579 ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId);
1581 if (!(type & 0xc0))
1582 WaitForSingleObject(ThreadHandle,INFINITE);
1584 CloseHandle(ThreadHandle);
1586 return ERROR_SUCCESS;
1589 static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source,
1590 const LPWSTR target, const INT type)
1592 WCHAR tmp_file[MAX_PATH];
1593 STARTUPINFOW si;
1594 PROCESS_INFORMATION info;
1595 BOOL rc;
1596 INT len;
1597 WCHAR *deformated;
1598 WCHAR *cmd;
1599 static const WCHAR spc[] = {' ',0};
1601 memset(&si,0,sizeof(STARTUPINFOW));
1603 store_binary_to_temp(package, source, tmp_file);
1605 deformat_string(package,target,&deformated);
1607 len = strlenW(tmp_file)+2;
1609 if (deformated)
1610 len += strlenW(deformated);
1612 cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len);
1614 strcpyW(cmd,tmp_file);
1615 if (deformated)
1617 strcatW(cmd,spc);
1618 strcatW(cmd,deformated);
1620 HeapFree(GetProcessHeap(),0,deformated);
1623 TRACE("executing exe %s \n",debugstr_w(cmd));
1625 rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
1626 c_collen, &si, &info);
1628 HeapFree(GetProcessHeap(),0,cmd);
1630 if ( !rc )
1632 ERR("Unable to execute command\n");
1633 return ERROR_SUCCESS;
1636 if (!(type & 0xc0))
1637 WaitForSingleObject(info.hProcess,INFINITE);
1639 CloseHandle( info.hProcess );
1640 CloseHandle( info.hThread );
1641 return ERROR_SUCCESS;
1644 static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source,
1645 const LPWSTR target, const INT type)
1647 STARTUPINFOW si;
1648 PROCESS_INFORMATION info;
1649 BOOL rc;
1650 WCHAR *deformated;
1651 WCHAR *cmd;
1652 INT len;
1653 static const WCHAR spc[] = {' ',0};
1654 int index;
1656 memset(&si,0,sizeof(STARTUPINFOW));
1658 index = get_loaded_file(package,source);
1660 len = strlenW(package->files[index].TargetPath);
1662 deformat_string(package,target,&deformated);
1663 if (deformated)
1664 len += strlenW(deformated);
1665 len += 2;
1667 cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,len * sizeof(WCHAR));
1669 strcpyW(cmd, package->files[index].TargetPath);
1670 if (deformated)
1672 strcatW(cmd, spc);
1673 strcatW(cmd, deformated);
1675 HeapFree(GetProcessHeap(),0,deformated);
1678 TRACE("executing exe %s \n",debugstr_w(cmd));
1680 rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
1681 c_collen, &si, &info);
1683 HeapFree(GetProcessHeap(),0,cmd);
1685 if ( !rc )
1687 ERR("Unable to execute command\n");
1688 return ERROR_SUCCESS;
1691 if (!(type & 0xc0))
1692 WaitForSingleObject(info.hProcess,INFINITE);
1694 CloseHandle( info.hProcess );
1695 CloseHandle( info.hThread );
1696 return ERROR_SUCCESS;
1699 static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source,
1700 const LPWSTR target, const INT type)
1702 STARTUPINFOW si;
1703 PROCESS_INFORMATION info;
1704 WCHAR *prop;
1705 BOOL rc;
1706 WCHAR *deformated;
1707 WCHAR *cmd;
1708 INT len;
1709 UINT prc;
1710 static const WCHAR spc[] = {' ',0};
1712 memset(&si,0,sizeof(STARTUPINFOW));
1713 memset(&info,0,sizeof(PROCESS_INFORMATION));
1715 prop = load_dynamic_property(package,source,&prc);
1716 if (!prop)
1717 return prc;
1719 deformat_string(package,target,&deformated);
1720 len = strlenW(prop) + 2;
1721 if (deformated)
1722 len += strlenW(deformated);
1724 cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len);
1726 strcpyW(cmd,prop);
1727 if (deformated)
1729 strcatW(cmd,spc);
1730 strcatW(cmd,deformated);
1732 HeapFree(GetProcessHeap(),0,deformated);
1735 TRACE("executing exe %s \n",debugstr_w(cmd));
1737 rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
1738 c_collen, &si, &info);
1740 HeapFree(GetProcessHeap(),0,cmd);
1742 if ( !rc )
1744 ERR("Unable to execute command\n");
1745 return ERROR_SUCCESS;
1748 if (!(type & 0xc0))
1749 WaitForSingleObject(info.hProcess,INFINITE);
1751 CloseHandle( info.hProcess );
1752 CloseHandle( info.hThread );
1753 return ERROR_SUCCESS;
1756 static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source,
1757 const LPWSTR target, const INT type)
1759 LPWSTR filename, deformated;
1760 STARTUPINFOW si;
1761 PROCESS_INFORMATION info;
1762 BOOL rc;
1764 memset(&si,0,sizeof(STARTUPINFOW));
1766 filename = resolve_folder(package, source, FALSE, FALSE, NULL);
1768 if (!filename)
1769 return ERROR_FUNCTION_FAILED;
1771 SetCurrentDirectoryW(filename);
1772 HeapFree(GetProcessHeap(),0,filename);
1774 deformat_string(package,target,&deformated);
1776 if (!deformated)
1777 return ERROR_FUNCTION_FAILED;
1779 TRACE("executing exe %s \n",debugstr_w(deformated));
1781 rc = CreateProcessW(NULL, deformated, NULL, NULL, FALSE, 0, NULL,
1782 c_collen, &si, &info);
1783 HeapFree(GetProcessHeap(),0,deformated);
1785 if ( !rc )
1787 ERR("Unable to execute command\n");
1788 return ERROR_SUCCESS;
1791 if (!(type & 0xc0))
1792 WaitForSingleObject(info.hProcess,INFINITE);
1794 CloseHandle( info.hProcess );
1795 CloseHandle( info.hThread );
1796 return ERROR_SUCCESS;
1799 /***********************************************************************
1800 * create_full_pathW
1802 * Recursively create all directories in the path.
1804 * shamelessly stolen from setupapi/queue.c
1806 static BOOL create_full_pathW(const WCHAR *path)
1808 BOOL ret = TRUE;
1809 int len;
1810 WCHAR *new_path;
1812 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *
1813 sizeof(WCHAR));
1815 strcpyW(new_path, path);
1817 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
1818 new_path[len - 1] = 0;
1820 while(!CreateDirectoryW(new_path, NULL))
1822 WCHAR *slash;
1823 DWORD last_error = GetLastError();
1824 if(last_error == ERROR_ALREADY_EXISTS)
1825 break;
1827 if(last_error != ERROR_PATH_NOT_FOUND)
1829 ret = FALSE;
1830 break;
1833 if(!(slash = strrchrW(new_path, '\\')))
1835 ret = FALSE;
1836 break;
1839 len = slash - new_path;
1840 new_path[len] = 0;
1841 if(!create_full_pathW(new_path))
1843 ret = FALSE;
1844 break;
1846 new_path[len] = '\\';
1849 HeapFree(GetProcessHeap(), 0, new_path);
1850 return ret;
1854 * Also we cannot enable/disable components either, so for now I am just going
1855 * to do all the directories for all the components.
1857 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1859 static const WCHAR ExecSeqQuery[] = {
1860 's','e','l','e','c','t',' ','D','i','r','e','c','t','o','r','y','_',' ',
1861 'f','r','o','m',' ','C','r','e','a','t','e','F','o','l','d','e','r',0 };
1862 UINT rc;
1863 MSIQUERY *view;
1864 MSIFOLDER *folder;
1866 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1867 if (rc != ERROR_SUCCESS)
1868 return ERROR_SUCCESS;
1870 rc = MSI_ViewExecute(view, 0);
1871 if (rc != ERROR_SUCCESS)
1873 MSI_ViewClose(view);
1874 msiobj_release(&view->hdr);
1875 return rc;
1878 while (1)
1880 WCHAR dir[0x100];
1881 LPWSTR full_path;
1882 DWORD sz;
1883 MSIRECORD *row = NULL, *uirow;
1885 rc = MSI_ViewFetch(view,&row);
1886 if (rc != ERROR_SUCCESS)
1888 rc = ERROR_SUCCESS;
1889 break;
1892 sz=0x100;
1893 rc = MSI_RecordGetStringW(row,1,dir,&sz);
1895 if (rc!= ERROR_SUCCESS)
1897 ERR("Unable to get folder id \n");
1898 msiobj_release(&row->hdr);
1899 continue;
1902 sz = MAX_PATH;
1903 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1904 if (!full_path)
1906 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1907 msiobj_release(&row->hdr);
1908 continue;
1911 TRACE("Folder is %s\n",debugstr_w(full_path));
1913 /* UI stuff */
1914 uirow = MSI_CreateRecord(1);
1915 MSI_RecordSetStringW(uirow,1,full_path);
1916 ui_actiondata(package,szCreateFolders,uirow);
1917 msiobj_release( &uirow->hdr );
1919 if (folder->State == 0)
1920 create_full_pathW(full_path);
1922 folder->State = 3;
1924 msiobj_release(&row->hdr);
1925 HeapFree(GetProcessHeap(),0,full_path);
1927 MSI_ViewClose(view);
1928 msiobj_release(&view->hdr);
1930 return rc;
1933 static int load_component(MSIPACKAGE* package, MSIRECORD * row)
1935 int index = package->loaded_components;
1936 DWORD sz;
1938 /* fill in the data */
1940 package->loaded_components++;
1941 if (package->loaded_components == 1)
1942 package->components = HeapAlloc(GetProcessHeap(),0,
1943 sizeof(MSICOMPONENT));
1944 else
1945 package->components = HeapReAlloc(GetProcessHeap(),0,
1946 package->components, package->loaded_components *
1947 sizeof(MSICOMPONENT));
1949 memset(&package->components[index],0,sizeof(MSICOMPONENT));
1951 sz = 96;
1952 MSI_RecordGetStringW(row,1,package->components[index].Component,&sz);
1954 TRACE("Loading Component %s\n",
1955 debugstr_w(package->components[index].Component));
1957 sz = 0x100;
1958 if (!MSI_RecordIsNull(row,2))
1959 MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz);
1961 sz = 96;
1962 MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz);
1964 package->components[index].Attributes = MSI_RecordGetInteger(row,4);
1966 sz = 0x100;
1967 MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz);
1969 sz = 96;
1970 MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);
1972 package->components[index].Installed = INSTALLSTATE_ABSENT;
1973 package->components[index].Action = INSTALLSTATE_UNKNOWN;
1974 package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN;
1976 package->components[index].Enabled = TRUE;
1978 return index;
1981 static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
1983 int index = package->loaded_features;
1984 DWORD sz;
1985 static const WCHAR Query1[] = {'S','E','L','E','C','T',' ','C','o','m','p',
1986 'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',
1987 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',
1988 'a','t','u','r','e','_','=','\'','%','s','\'',0};
1989 static const WCHAR Query2[] = {'S','E','L','E','C','T',' ','*',' ','F','R',
1990 'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',
1991 'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};
1992 MSIQUERY * view;
1993 MSIQUERY * view2;
1994 MSIRECORD * row2;
1995 MSIRECORD * row3;
1996 UINT rc;
1998 /* fill in the data */
2000 package->loaded_features ++;
2001 if (package->loaded_features == 1)
2002 package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE));
2003 else
2004 package->features = HeapReAlloc(GetProcessHeap(),0,package->features,
2005 package->loaded_features * sizeof(MSIFEATURE));
2007 memset(&package->features[index],0,sizeof(MSIFEATURE));
2009 sz = 96;
2010 MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz);
2012 TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature));
2014 sz = 96;
2015 if (!MSI_RecordIsNull(row,2))
2016 MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz);
2018 sz = 0x100;
2019 if (!MSI_RecordIsNull(row,3))
2020 MSI_RecordGetStringW(row,3,package->features[index].Title,&sz);
2022 sz = 0x100;
2023 if (!MSI_RecordIsNull(row,4))
2024 MSI_RecordGetStringW(row,4,package->features[index].Description,&sz);
2026 if (!MSI_RecordIsNull(row,5))
2027 package->features[index].Display = MSI_RecordGetInteger(row,5);
2029 package->features[index].Level= MSI_RecordGetInteger(row,6);
2031 sz = 96;
2032 if (!MSI_RecordIsNull(row,7))
2033 MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);
2035 package->features[index].Attributes= MSI_RecordGetInteger(row,8);
2037 package->features[index].Installed = INSTALLSTATE_ABSENT;
2038 package->features[index].Action = INSTALLSTATE_UNKNOWN;
2039 package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN;
2041 /* load feature components */
2043 rc = MSI_OpenQuery(package->db, &view, Query1, package->features[index].Feature);
2044 if (rc != ERROR_SUCCESS)
2045 return;
2046 rc = MSI_ViewExecute(view,0);
2047 if (rc != ERROR_SUCCESS)
2049 MSI_ViewClose(view);
2050 msiobj_release(&view->hdr);
2051 return;
2053 while (1)
2055 DWORD sz = 0x100;
2056 WCHAR buffer[0x100];
2057 DWORD rc;
2058 INT c_indx;
2059 INT cnt = package->features[index].ComponentCount;
2061 rc = MSI_ViewFetch(view,&row2);
2062 if (rc != ERROR_SUCCESS)
2063 break;
2065 sz = 0x100;
2066 MSI_RecordGetStringW(row2,1,buffer,&sz);
2068 /* check to see if the component is already loaded */
2069 c_indx = get_loaded_component(package,buffer);
2070 if (c_indx != -1)
2072 TRACE("Component %s already loaded at %i\n", debugstr_w(buffer),
2073 c_indx);
2074 package->features[index].Components[cnt] = c_indx;
2075 package->features[index].ComponentCount ++;
2076 continue;
2079 rc = MSI_OpenQuery(package->db, &view2, Query2, buffer);
2080 if (rc != ERROR_SUCCESS)
2082 msiobj_release( &row2->hdr );
2083 continue;
2085 rc = MSI_ViewExecute(view2,0);
2086 if (rc != ERROR_SUCCESS)
2088 msiobj_release( &row2->hdr );
2089 MSI_ViewClose(view2);
2090 msiobj_release( &view2->hdr );
2091 continue;
2093 while (1)
2095 DWORD rc;
2097 rc = MSI_ViewFetch(view2,&row3);
2098 if (rc != ERROR_SUCCESS)
2099 break;
2100 c_indx = load_component(package,row3);
2101 msiobj_release( &row3->hdr );
2103 package->features[index].Components[cnt] = c_indx;
2104 package->features[index].ComponentCount ++;
2105 TRACE("Loaded new component to index %i\n",c_indx);
2107 MSI_ViewClose(view2);
2108 msiobj_release( &view2->hdr );
2109 msiobj_release( &row2->hdr );
2111 MSI_ViewClose(view);
2112 msiobj_release(&view->hdr);
2116 * I am not doing any of the costing functionality yet.
2117 * Mostly looking at doing the Component and Feature loading
2119 * The native MSI does ALOT of modification to tables here. Mostly adding alot
2120 * of temporary columns to the Feature and Component tables.
2122 * note: native msi also tracks the short filename. but I am only going to
2123 * track the long ones. Also looking at this directory table
2124 * it appears that the directory table does not get the parents
2125 * resolved base on property only based on their entrys in the
2126 * directory table.
2128 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
2130 MSIQUERY * view;
2131 MSIRECORD * row;
2132 UINT rc;
2133 static const WCHAR Query_all[] = {
2134 'S','E','L','E','C','T',' ','*',' ',
2135 'F','R','O','M',' ','F','e','a','t','u','r','e',0};
2136 static const WCHAR szCosting[] = {
2137 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2138 static const WCHAR szZero[] = { '0', 0 };
2140 MSI_SetPropertyW(package, szCosting, szZero);
2141 MSI_SetPropertyW(package, cszRootDrive , c_collen);
2143 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
2144 if (rc != ERROR_SUCCESS)
2145 return rc;
2146 rc = MSI_ViewExecute(view,0);
2147 if (rc != ERROR_SUCCESS)
2149 MSI_ViewClose(view);
2150 msiobj_release(&view->hdr);
2151 return rc;
2153 while (1)
2155 DWORD rc;
2157 rc = MSI_ViewFetch(view,&row);
2158 if (rc != ERROR_SUCCESS)
2159 break;
2161 load_feature(package,row);
2162 msiobj_release(&row->hdr);
2164 MSI_ViewClose(view);
2165 msiobj_release(&view->hdr);
2167 return ERROR_SUCCESS;
2170 static UINT load_file(MSIPACKAGE* package, MSIRECORD * row)
2172 DWORD index = package->loaded_files;
2173 DWORD i;
2174 LPWSTR buffer;
2176 /* fill in the data */
2178 package->loaded_files++;
2179 if (package->loaded_files== 1)
2180 package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
2181 else
2182 package->files = HeapReAlloc(GetProcessHeap(),0,
2183 package->files , package->loaded_files * sizeof(MSIFILE));
2185 memset(&package->files[index],0,sizeof(MSIFILE));
2187 package->files[index].File = load_dynamic_stringW(row, 1);
2188 buffer = load_dynamic_stringW(row, 2);
2190 package->files[index].ComponentIndex = -1;
2191 for (i = 0; i < package->loaded_components; i++)
2192 if (strcmpW(package->components[i].Component,buffer)==0)
2194 package->files[index].ComponentIndex = i;
2195 break;
2197 if (package->files[index].ComponentIndex == -1)
2198 ERR("Unfound Component %s\n",debugstr_w(buffer));
2199 HeapFree(GetProcessHeap(), 0, buffer);
2201 package->files[index].FileName = load_dynamic_stringW(row,3);
2203 reduce_to_longfilename(package->files[index].FileName);
2205 package->files[index].FileSize = MSI_RecordGetInteger(row,4);
2206 package->files[index].Version = load_dynamic_stringW(row, 5);
2207 package->files[index].Language = load_dynamic_stringW(row, 6);
2208 package->files[index].Attributes= MSI_RecordGetInteger(row,7);
2209 package->files[index].Sequence= MSI_RecordGetInteger(row,8);
2211 package->files[index].Temporary = FALSE;
2212 package->files[index].State = 0;
2214 TRACE("File Loaded (%s)\n",debugstr_w(package->files[index].File));
2216 return ERROR_SUCCESS;
2219 static UINT ACTION_FileCost(MSIPACKAGE *package)
2221 MSIQUERY * view;
2222 MSIRECORD * row;
2223 UINT rc;
2224 static const WCHAR Query[] = {
2225 'S','E','L','E','C','T',' ','*',' ',
2226 'F','R','O','M',' ','F','i','l','e',' ',
2227 'O','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e', 0};
2229 if (!package)
2230 return ERROR_INVALID_HANDLE;
2232 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2233 if (rc != ERROR_SUCCESS)
2234 return ERROR_SUCCESS;
2236 rc = MSI_ViewExecute(view, 0);
2237 if (rc != ERROR_SUCCESS)
2239 MSI_ViewClose(view);
2240 msiobj_release(&view->hdr);
2241 return ERROR_SUCCESS;
2244 while (1)
2246 rc = MSI_ViewFetch(view,&row);
2247 if (rc != ERROR_SUCCESS)
2249 rc = ERROR_SUCCESS;
2250 break;
2252 load_file(package,row);
2253 msiobj_release(&row->hdr);
2255 MSI_ViewClose(view);
2256 msiobj_release(&view->hdr);
2258 return ERROR_SUCCESS;
2261 static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)
2264 static const WCHAR Query[] =
2265 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',
2266 't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',
2267 'o','r','y','`',' ','=',' ','`','%','s','`',0};
2268 UINT rc;
2269 MSIQUERY * view;
2270 LPWSTR targetdir, parent, srcdir;
2271 MSIRECORD * row = 0;
2272 INT index = -1;
2273 DWORD i;
2275 TRACE("Looking for dir %s\n",debugstr_w(dir));
2277 for (i = 0; i < package->loaded_folders; i++)
2279 if (strcmpW(package->folders[i].Directory,dir)==0)
2281 TRACE(" %s retuning on index %lu\n",debugstr_w(dir),i);
2282 return i;
2286 TRACE("Working to load %s\n",debugstr_w(dir));
2288 index = package->loaded_folders++;
2289 if (package->loaded_folders==1)
2290 package->folders = HeapAlloc(GetProcessHeap(),0,
2291 sizeof(MSIFOLDER));
2292 else
2293 package->folders= HeapReAlloc(GetProcessHeap(),0,
2294 package->folders, package->loaded_folders*
2295 sizeof(MSIFOLDER));
2297 memset(&package->folders[index],0,sizeof(MSIFOLDER));
2299 package->folders[index].Directory = dupstrW(dir);
2301 rc = MSI_OpenQuery(package->db, &view, Query, dir);
2302 if (rc != ERROR_SUCCESS)
2303 return -1;
2305 rc = MSI_ViewExecute(view, 0);
2306 if (rc != ERROR_SUCCESS)
2308 MSI_ViewClose(view);
2309 msiobj_release(&view->hdr);
2310 return -1;
2313 rc = MSI_ViewFetch(view,&row);
2314 if (rc != ERROR_SUCCESS)
2316 MSI_ViewClose(view);
2317 msiobj_release(&view->hdr);
2318 return -1;
2321 targetdir = load_dynamic_stringW(row,3);
2323 /* split src and target dir */
2324 if (strchrW(targetdir,':'))
2326 srcdir=strchrW(targetdir,':');
2327 *srcdir=0;
2328 srcdir ++;
2330 else
2331 srcdir=NULL;
2333 /* for now only pick long filename versions */
2334 if (strchrW(targetdir,'|'))
2336 targetdir = strchrW(targetdir,'|');
2337 *targetdir = 0;
2338 targetdir ++;
2340 if (srcdir && strchrW(srcdir,'|'))
2342 srcdir= strchrW(srcdir,'|');
2343 *srcdir= 0;
2344 srcdir ++;
2347 /* now check for root dirs */
2348 if (targetdir[0] == '.' && targetdir[1] == 0)
2349 targetdir = NULL;
2351 if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
2352 srcdir = NULL;
2354 if (targetdir)
2356 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
2357 HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault);
2358 package->folders[index].TargetDefault = dupstrW(targetdir);
2361 if (srcdir)
2362 package->folders[index].SourceDefault = dupstrW(srcdir);
2363 else if (targetdir)
2364 package->folders[index].SourceDefault = dupstrW(targetdir);
2365 HeapFree(GetProcessHeap(), 0, targetdir);
2367 parent = load_dynamic_stringW(row,2);
2368 if (parent)
2370 i = load_folder(package,parent);
2371 package->folders[index].ParentIndex = i;
2372 TRACE("Parent is index %i... %s %s\n",
2373 package->folders[index].ParentIndex,
2374 debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),
2375 debugstr_w(parent));
2377 else
2378 package->folders[index].ParentIndex = -2;
2379 HeapFree(GetProcessHeap(), 0, parent);
2381 package->folders[index].Property = load_dynamic_property(package, dir,NULL);
2383 msiobj_release(&row->hdr);
2384 MSI_ViewClose(view);
2385 msiobj_release(&view->hdr);
2386 TRACE(" %s retuning on index %i\n",debugstr_w(dir),index);
2387 return index;
2391 static LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name,
2392 BOOL source, BOOL set_prop, MSIFOLDER **folder)
2394 DWORD i;
2395 LPWSTR p, path = NULL;
2397 TRACE("Working to resolve %s\n",debugstr_w(name));
2399 /* special resolving for Target and Source root dir */
2400 if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
2402 if (!source)
2404 path = load_dynamic_property(package,cszTargetDir,NULL);
2405 if (!path)
2407 path = load_dynamic_property(package,cszRootDrive,NULL);
2408 if (set_prop)
2409 MSI_SetPropertyW(package,cszTargetDir,path);
2411 if (folder)
2413 for (i = 0; i < package->loaded_folders; i++)
2415 if (strcmpW(package->folders[i].Directory,name)==0)
2416 break;
2418 *folder = &(package->folders[i]);
2420 return path;
2422 else
2424 path = load_dynamic_property(package,cszSourceDir,NULL);
2425 if (!path)
2427 path = load_dynamic_property(package,cszDatabase,NULL);
2428 if (path)
2430 p = strrchrW(path,'\\');
2431 if (p)
2432 *(p+1) = 0;
2435 if (folder)
2437 for (i = 0; i < package->loaded_folders; i++)
2439 if (strcmpW(package->folders[i].Directory,name)==0)
2440 break;
2442 *folder = &(package->folders[i]);
2444 return path;
2448 for (i = 0; i < package->loaded_folders; i++)
2450 if (strcmpW(package->folders[i].Directory,name)==0)
2451 break;
2454 if (i >= package->loaded_folders)
2455 return NULL;
2457 if (folder)
2458 *folder = &(package->folders[i]);
2460 if (!source && package->folders[i].ResolvedTarget)
2462 path = dupstrW(package->folders[i].ResolvedTarget);
2463 TRACE(" already resolved to %s\n",debugstr_w(path));
2464 return path;
2466 else if (source && package->folders[i].ResolvedSource)
2468 path = dupstrW(package->folders[i].ResolvedSource);
2469 return path;
2471 else if (!source && package->folders[i].Property)
2473 path = dupstrW(package->folders[i].Property);
2474 TRACE(" internally set to %s\n",debugstr_w(path));
2475 if (set_prop)
2476 MSI_SetPropertyW(package,name,path);
2477 return path;
2480 if (package->folders[i].ParentIndex >= 0)
2482 LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;
2484 TRACE(" ! Parent is %s\n", debugstr_w(parent));
2486 p = resolve_folder(package, parent, source, set_prop, NULL);
2487 if (!source)
2489 TRACE(" TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault));
2490 path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL);
2491 package->folders[i].ResolvedTarget = dupstrW(path);
2492 TRACE(" resolved into %s\n",debugstr_w(path));
2493 if (set_prop)
2494 MSI_SetPropertyW(package,name,path);
2496 else
2498 path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);
2499 package->folders[i].ResolvedSource = dupstrW(path);
2501 HeapFree(GetProcessHeap(),0,p);
2503 return path;
2506 static UINT SetFeatureStates(MSIPACKAGE *package)
2508 LPWSTR level;
2509 INT install_level;
2510 DWORD i;
2511 INT j;
2512 LPWSTR override = NULL;
2513 static const WCHAR all[]={'A','L','L',0};
2514 static const WCHAR szlevel[] = {
2515 'I','N','S','T','A','L','L','L','E','V','E','L',0};
2516 static const WCHAR szAddLocal[] = {
2517 'A','D','D','L','O','C','A','L',0};
2519 /* I do not know if this is where it should happen.. but */
2521 TRACE("Checking Install Level\n");
2523 level = load_dynamic_property(package,szlevel,NULL);
2524 if (level)
2526 install_level = atoiW(level);
2527 HeapFree(GetProcessHeap(), 0, level);
2529 else
2530 install_level = 1;
2532 /* ok hereis the rub
2533 * ADDLOCAL and its friend OVERRIDE INSTALLLEVLE
2534 * I have confirmed this if ADDLOCALis stated then the INSTALLLEVEL is
2535 * itnored for all the features. seems strange, epsecially since it is not
2536 * documented anywhere, but it is how it works.
2539 override = load_dynamic_property(package,szAddLocal,NULL);
2541 if (override)
2543 for(i = 0; i < package->loaded_features; i++)
2545 if (strcmpiW(override,all)==0)
2547 package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
2548 package->features[i].Action = INSTALLSTATE_LOCAL;
2550 else
2552 LPWSTR ptr = override;
2553 LPWSTR ptr2 = strchrW(override,',');
2555 while (ptr)
2557 if ((ptr2 &&
2558 strncmpW(ptr,package->features[i].Feature, ptr2-ptr)==0)
2559 || (!ptr2 &&
2560 strcmpW(ptr,package->features[i].Feature)==0))
2562 package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
2563 package->features[i].Action = INSTALLSTATE_LOCAL;
2564 break;
2566 if (ptr2)
2568 ptr=ptr2+1;
2569 ptr2 = strchrW(ptr,',');
2571 else
2572 break;
2576 HeapFree(GetProcessHeap(),0,override);
2578 else
2580 for(i = 0; i < package->loaded_features; i++)
2582 BOOL feature_state= ((package->features[i].Level > 0) &&
2583 (package->features[i].Level <= install_level));
2585 if (feature_state)
2587 package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
2588 package->features[i].Action = INSTALLSTATE_LOCAL;
2594 * now we want to enable or disable components base on feature
2597 for(i = 0; i < package->loaded_features; i++)
2599 MSIFEATURE* feature = &package->features[i];
2600 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
2601 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2602 feature->ActionRequest);
2604 for( j = 0; j < feature->ComponentCount; j++)
2606 MSICOMPONENT* component = &package->components[
2607 feature->Components[j]];
2609 if (!component->Enabled)
2611 component->Action = INSTALLSTATE_ABSENT;
2612 component->ActionRequest = INSTALLSTATE_ABSENT;
2614 else
2616 if (feature->Action == INSTALLSTATE_LOCAL)
2617 component->Action = INSTALLSTATE_LOCAL;
2618 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
2619 component->ActionRequest = INSTALLSTATE_LOCAL;
2624 for(i = 0; i < package->loaded_components; i++)
2626 MSICOMPONENT* component= &package->components[i];
2628 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
2629 debugstr_w(component->Component), component->Installed,
2630 component->Action, component->ActionRequest);
2634 return ERROR_SUCCESS;
2638 * Alot is done in this function aside from just the costing.
2639 * The costing needs to be implemented at some point but for now I am going
2640 * to focus on the directory building
2643 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2645 static const WCHAR ExecSeqQuery[] = {
2646 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2647 'D','i','r','e','c','t','o','r','y',0};
2648 static const WCHAR ConditionQuery[] = {
2649 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2650 'C','o','n','d','i','t','i','o','n',0};
2651 static const WCHAR szCosting[] = {
2652 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2653 static const WCHAR szlevel[] = {
2654 'I','N','S','T','A','L','L','L','E','V','E','L',0};
2655 static const WCHAR szOne[] = { '1', 0 };
2656 UINT rc;
2657 MSIQUERY * view;
2658 DWORD i;
2659 LPWSTR level;
2661 TRACE("Building Directory properties\n");
2663 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2664 if (rc == ERROR_SUCCESS)
2666 rc = MSI_ViewExecute(view, 0);
2667 if (rc != ERROR_SUCCESS)
2669 MSI_ViewClose(view);
2670 msiobj_release(&view->hdr);
2671 return rc;
2674 while (1)
2676 WCHAR name[0x100];
2677 LPWSTR path;
2678 MSIRECORD * row = 0;
2679 DWORD sz;
2681 rc = MSI_ViewFetch(view,&row);
2682 if (rc != ERROR_SUCCESS)
2684 rc = ERROR_SUCCESS;
2685 break;
2688 sz=0x100;
2689 MSI_RecordGetStringW(row,1,name,&sz);
2691 /* This helper function now does ALL the work */
2692 TRACE("Dir %s ...\n",debugstr_w(name));
2693 load_folder(package,name);
2694 path = resolve_folder(package,name,FALSE,TRUE,NULL);
2695 TRACE("resolves to %s\n",debugstr_w(path));
2696 HeapFree( GetProcessHeap(), 0, path);
2698 msiobj_release(&row->hdr);
2700 MSI_ViewClose(view);
2701 msiobj_release(&view->hdr);
2704 TRACE("File calculations %i files\n",package->loaded_files);
2706 for (i = 0; i < package->loaded_files; i++)
2708 MSICOMPONENT* comp = NULL;
2709 MSIFILE* file= NULL;
2711 file = &package->files[i];
2712 if (file->ComponentIndex >= 0)
2713 comp = &package->components[file->ComponentIndex];
2715 if (file->Temporary == TRUE)
2716 continue;
2718 if (comp)
2720 LPWSTR p;
2722 /* calculate target */
2723 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
2725 HeapFree(GetProcessHeap(),0,file->TargetPath);
2727 TRACE("file %s is named %s\n",
2728 debugstr_w(file->File),debugstr_w(file->FileName));
2730 file->TargetPath = build_directory_name(2, p, file->FileName);
2732 HeapFree(GetProcessHeap(),0,p);
2734 TRACE("file %s resolves to %s\n",
2735 debugstr_w(file->File),debugstr_w(file->TargetPath));
2737 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2739 file->State = 1;
2740 comp->Cost += file->FileSize;
2742 else
2744 if (file->Version)
2746 DWORD handle;
2747 DWORD versize;
2748 UINT sz;
2749 LPVOID version;
2750 static const WCHAR name[] =
2751 {'\\',0};
2752 static const WCHAR name_fmt[] =
2753 {'%','u','.','%','u','.','%','u','.','%','u',0};
2754 WCHAR filever[0x100];
2755 VS_FIXEDFILEINFO *lpVer;
2757 TRACE("Version comparison.. \n");
2758 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
2759 version = HeapAlloc(GetProcessHeap(),0,versize);
2760 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
2762 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
2764 sprintfW(filever,name_fmt,
2765 HIWORD(lpVer->dwFileVersionMS),
2766 LOWORD(lpVer->dwFileVersionMS),
2767 HIWORD(lpVer->dwFileVersionLS),
2768 LOWORD(lpVer->dwFileVersionLS));
2770 TRACE("new %s old %s\n", debugstr_w(file->Version),
2771 debugstr_w(filever));
2772 if (strcmpiW(filever,file->Version)<0)
2774 file->State = 2;
2775 FIXME("cost should be diff in size\n");
2776 comp->Cost += file->FileSize;
2778 else
2779 file->State = 3;
2780 HeapFree(GetProcessHeap(),0,version);
2782 else
2783 file->State = 3;
2788 TRACE("Evaluating Condition Table\n");
2790 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2791 if (rc == ERROR_SUCCESS)
2793 rc = MSI_ViewExecute(view, 0);
2794 if (rc != ERROR_SUCCESS)
2796 MSI_ViewClose(view);
2797 msiobj_release(&view->hdr);
2798 return rc;
2801 while (1)
2803 WCHAR Feature[0x100];
2804 MSIRECORD * row = 0;
2805 DWORD sz;
2806 int feature_index;
2808 rc = MSI_ViewFetch(view,&row);
2810 if (rc != ERROR_SUCCESS)
2812 rc = ERROR_SUCCESS;
2813 break;
2816 sz = 0x100;
2817 MSI_RecordGetStringW(row,1,Feature,&sz);
2819 feature_index = get_loaded_feature(package,Feature);
2820 if (feature_index < 0)
2821 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));
2822 else
2824 LPWSTR Condition;
2825 Condition = load_dynamic_stringW(row,3);
2827 if (MSI_EvaluateConditionW(package,Condition) ==
2828 MSICONDITION_TRUE)
2830 int level = MSI_RecordGetInteger(row,2);
2831 TRACE("Reseting feature %s to level %i\n",
2832 debugstr_w(Feature), level);
2833 package->features[feature_index].Level = level;
2835 HeapFree(GetProcessHeap(),0,Condition);
2838 msiobj_release(&row->hdr);
2840 MSI_ViewClose(view);
2841 msiobj_release(&view->hdr);
2844 TRACE("Enabling or Disabling Components\n");
2845 for (i = 0; i < package->loaded_components; i++)
2847 if (package->components[i].Condition[0])
2849 if (MSI_EvaluateConditionW(package,
2850 package->components[i].Condition) == MSICONDITION_FALSE)
2852 TRACE("Disabling component %s\n",
2853 debugstr_w(package->components[i].Component));
2854 package->components[i].Enabled = FALSE;
2859 MSI_SetPropertyW(package,szCosting,szOne);
2860 /* set default run level if not set */
2861 level = load_dynamic_property(package,szlevel,NULL);
2862 if (!level)
2863 MSI_SetPropertyW(package,szlevel, szOne);
2864 else
2865 HeapFree(GetProcessHeap(),0,level);
2867 return SetFeatureStates(package);
2872 * This is a helper function for handling embedded cabinet media
2874 static UINT writeout_cabinet_stream(MSIPACKAGE *package, WCHAR* stream_name,
2875 WCHAR* source)
2877 UINT rc;
2878 USHORT* data;
2879 UINT size;
2880 DWORD write;
2881 HANDLE the_file;
2882 WCHAR tmp[MAX_PATH];
2884 rc = read_raw_stream_data(package->db,stream_name,&data,&size);
2885 if (rc != ERROR_SUCCESS)
2886 return rc;
2888 write = MAX_PATH;
2889 if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
2890 GetTempPathW(MAX_PATH,tmp);
2892 GetTempFileNameW(tmp,stream_name,0,source);
2894 track_tempfile(package,strrchrW(source,'\\'), source);
2895 the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2896 FILE_ATTRIBUTE_NORMAL, NULL);
2898 if (the_file == INVALID_HANDLE_VALUE)
2900 rc = ERROR_FUNCTION_FAILED;
2901 goto end;
2904 WriteFile(the_file,data,size,&write,NULL);
2905 CloseHandle(the_file);
2906 TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
2907 end:
2908 HeapFree(GetProcessHeap(),0,data);
2909 return rc;
2913 /* Support functions for FDI functions */
2914 typedef struct
2916 MSIPACKAGE* package;
2917 LPCSTR cab_path;
2918 LPCSTR file_name;
2919 } CabData;
2921 static void * cabinet_alloc(ULONG cb)
2923 return HeapAlloc(GetProcessHeap(), 0, cb);
2926 static void cabinet_free(void *pv)
2928 HeapFree(GetProcessHeap(), 0, pv);
2931 static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
2933 DWORD dwAccess = 0;
2934 DWORD dwShareMode = 0;
2935 DWORD dwCreateDisposition = OPEN_EXISTING;
2936 switch (oflag & _O_ACCMODE)
2938 case _O_RDONLY:
2939 dwAccess = GENERIC_READ;
2940 dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
2941 break;
2942 case _O_WRONLY:
2943 dwAccess = GENERIC_WRITE;
2944 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2945 break;
2946 case _O_RDWR:
2947 dwAccess = GENERIC_READ | GENERIC_WRITE;
2948 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2949 break;
2951 if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
2952 dwCreateDisposition = CREATE_NEW;
2953 else if (oflag & _O_CREAT)
2954 dwCreateDisposition = CREATE_ALWAYS;
2955 return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL, dwCreateDisposition, 0, NULL);
2958 static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
2960 DWORD dwRead;
2961 if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
2962 return dwRead;
2963 return 0;
2966 static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
2968 DWORD dwWritten;
2969 if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
2970 return dwWritten;
2971 return 0;
2974 static int cabinet_close(INT_PTR hf)
2976 return CloseHandle((HANDLE)hf) ? 0 : -1;
2979 static long cabinet_seek(INT_PTR hf, long dist, int seektype)
2981 /* flags are compatible and so are passed straight through */
2982 return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
2985 static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
2987 /* FIXME: try to do more processing in this function */
2988 switch (fdint)
2990 case fdintCOPY_FILE:
2992 CabData *data = (CabData*) pfdin->pv;
2993 ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
2994 char *file;
2996 LPWSTR trackname;
2997 LPWSTR trackpath;
2998 LPWSTR tracknametmp;
2999 static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
3001 if (data->file_name && strcmp(data->file_name,pfdin->psz1))
3002 return 0;
3004 file = cabinet_alloc((len+1)*sizeof(char));
3005 strcpy(file, data->cab_path);
3006 strcat(file, pfdin->psz1);
3008 TRACE("file: %s\n", debugstr_a(file));
3010 /* track this file so it can be deleted if not installed */
3011 trackpath=strdupAtoW(file);
3012 tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
3013 trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) +
3014 strlenW(tmpprefix)+1) * sizeof(WCHAR));
3016 strcpyW(trackname,tmpprefix);
3017 strcatW(trackname,tracknametmp);
3019 track_tempfile(data->package, trackname, trackpath);
3021 HeapFree(GetProcessHeap(),0,trackpath);
3022 HeapFree(GetProcessHeap(),0,trackname);
3023 HeapFree(GetProcessHeap(),0,tracknametmp);
3025 return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
3027 case fdintCLOSE_FILE_INFO:
3029 FILETIME ft;
3030 FILETIME ftLocal;
3031 if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
3032 return -1;
3033 if (!LocalFileTimeToFileTime(&ft, &ftLocal))
3034 return -1;
3035 if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
3036 return -1;
3038 cabinet_close(pfdin->hf);
3039 return 1;
3041 default:
3042 return 0;
3046 /***********************************************************************
3047 * extract_cabinet_file
3049 * Extract files from a cab file.
3051 static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source,
3052 const WCHAR* path, const WCHAR* file)
3054 HFDI hfdi;
3055 ERF erf;
3056 BOOL ret;
3057 char *cabinet;
3058 char *cab_path;
3059 char *file_name;
3060 CabData data;
3062 TRACE("Extracting %s (%s) to %s\n",debugstr_w(source),
3063 debugstr_w(file), debugstr_w(path));
3065 hfdi = FDICreate(cabinet_alloc,
3066 cabinet_free,
3067 cabinet_open,
3068 cabinet_read,
3069 cabinet_write,
3070 cabinet_close,
3071 cabinet_seek,
3073 &erf);
3074 if (!hfdi)
3076 ERR("FDICreate failed\n");
3077 return FALSE;
3080 if (!(cabinet = strdupWtoA( source )))
3082 FDIDestroy(hfdi);
3083 return FALSE;
3085 if (!(cab_path = strdupWtoA( path )))
3087 FDIDestroy(hfdi);
3088 HeapFree(GetProcessHeap(), 0, cabinet);
3089 return FALSE;
3092 data.package = package;
3093 data.cab_path = cab_path;
3094 file_name = strdupWtoA(file);
3095 data.file_name = file_name;
3097 ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
3099 if (!ret)
3100 ERR("FDICopy failed\n");
3102 FDIDestroy(hfdi);
3104 HeapFree(GetProcessHeap(), 0, cabinet);
3105 HeapFree(GetProcessHeap(), 0, cab_path);
3106 HeapFree(GetProcessHeap(), 0, file_name);
3108 return ret;
3111 static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence,
3112 WCHAR* path, WCHAR* file)
3114 UINT rc;
3115 MSIQUERY * view;
3116 MSIRECORD * row = 0;
3117 static WCHAR source[MAX_PATH];
3118 static const WCHAR ExecSeqQuery[] = {
3119 's','e','l','e','c','t',' ','*',' ',
3120 'f','r','o','m',' ','M','e','d','i','a',' ',
3121 'w','h','e','r','e',' ','L','a','s','t','S','e','q','u','e','n','c','e',' ','>','=',' ','%','i',' ',
3122 'o','r','d','e','r',' ','b','y',' ','L','a','s','t','S','e','q','u','e','n','c','e',0};
3123 WCHAR Query[1024];
3124 WCHAR cab[0x100];
3125 DWORD sz=0x100;
3126 INT seq;
3127 static UINT last_sequence = 0;
3129 if (sequence <= last_sequence)
3131 TRACE("Media already ready (%u, %u)\n",sequence,last_sequence);
3132 extract_a_cabinet_file(package, source,path,file);
3133 return ERROR_SUCCESS;
3136 sprintfW(Query,ExecSeqQuery,sequence);
3138 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3139 if (rc != ERROR_SUCCESS)
3140 return rc;
3142 rc = MSI_ViewExecute(view, 0);
3143 if (rc != ERROR_SUCCESS)
3145 MSI_ViewClose(view);
3146 msiobj_release(&view->hdr);
3147 return rc;
3150 rc = MSI_ViewFetch(view,&row);
3151 if (rc != ERROR_SUCCESS)
3153 MSI_ViewClose(view);
3154 msiobj_release(&view->hdr);
3155 return rc;
3157 seq = MSI_RecordGetInteger(row,2);
3158 last_sequence = seq;
3160 if (!MSI_RecordIsNull(row,4))
3162 sz=0x100;
3163 MSI_RecordGetStringW(row,4,cab,&sz);
3164 TRACE("Source is CAB %s\n",debugstr_w(cab));
3165 /* the stream does not contain the # character */
3166 if (cab[0]=='#')
3168 writeout_cabinet_stream(package,&cab[1],source);
3169 strcpyW(path,source);
3170 *(strrchrW(path,'\\')+1)=0;
3172 else
3174 sz = MAX_PATH;
3175 if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
3177 ERR("No Source dir defined \n");
3178 rc = ERROR_FUNCTION_FAILED;
3180 else
3182 strcpyW(path,source);
3183 strcatW(source,cab);
3184 /* extract the cab file into a folder in the temp folder */
3185 sz = MAX_PATH;
3186 if (MSI_GetPropertyW(package, cszTempFolder,path, &sz)
3187 != ERROR_SUCCESS)
3188 GetTempPathW(MAX_PATH,path);
3191 rc = !extract_a_cabinet_file(package, source,path,file);
3193 msiobj_release(&row->hdr);
3194 MSI_ViewClose(view);
3195 msiobj_release(&view->hdr);
3196 return rc;
3199 inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
3201 UINT rc = ERROR_SUCCESS;
3202 MSIFOLDER *folder;
3203 LPWSTR install_path;
3205 install_path = resolve_folder(package, package->components[component].Directory,
3206 FALSE, FALSE, &folder);
3207 if (!install_path)
3208 return ERROR_FUNCTION_FAILED;
3210 /* create the path */
3211 if (folder->State == 0)
3213 create_full_pathW(install_path);
3214 folder->State = 2;
3216 HeapFree(GetProcessHeap(), 0, install_path);
3218 return rc;
3221 static UINT ACTION_InstallFiles(MSIPACKAGE *package)
3223 UINT rc = ERROR_SUCCESS;
3224 DWORD index;
3225 MSIRECORD * uirow;
3226 WCHAR uipath[MAX_PATH];
3228 if (!package)
3229 return ERROR_INVALID_HANDLE;
3231 /* increment progress bar each time action data is sent */
3232 ui_progress(package,1,1,0,0);
3234 for (index = 0; index < package->loaded_files; index++)
3236 WCHAR path_to_source[MAX_PATH];
3237 MSIFILE *file;
3239 file = &package->files[index];
3241 if (file->Temporary)
3242 continue;
3244 if (package->components[file->ComponentIndex].ActionRequest !=
3245 INSTALLSTATE_LOCAL)
3247 ui_progress(package,2,file->FileSize,0,0);
3248 TRACE("File %s is not scheduled for install\n",
3249 debugstr_w(file->File));
3251 continue;
3254 if ((file->State == 1) || (file->State == 2))
3256 LPWSTR p;
3257 INT len;
3258 MSICOMPONENT* comp = NULL;
3260 TRACE("Installing %s\n",debugstr_w(file->File));
3261 rc = ready_media_for_file(package,file->Sequence,path_to_source,
3262 file->File);
3264 * WARNING!
3265 * our file table could change here because a new temp file
3266 * may have been created
3268 file = &package->files[index];
3269 if (rc != ERROR_SUCCESS)
3271 ERR("Unable to ready media\n");
3272 rc = ERROR_FUNCTION_FAILED;
3273 break;
3276 create_component_directory( package, file->ComponentIndex);
3278 /* recalculate file paths because things may have changed */
3280 if (file->ComponentIndex >= 0)
3281 comp = &package->components[file->ComponentIndex];
3283 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
3284 HeapFree(GetProcessHeap(),0,file->TargetPath);
3286 file->TargetPath = build_directory_name(2, p, file->FileName);
3288 len = strlenW(path_to_source) + strlenW(file->File) + 2;
3289 file->SourcePath = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
3290 strcpyW(file->SourcePath, path_to_source);
3291 strcatW(file->SourcePath, file->File);
3293 TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
3294 debugstr_w(file->TargetPath));
3296 /* the UI chunk */
3297 uirow=MSI_CreateRecord(9);
3298 MSI_RecordSetStringW(uirow,1,file->File);
3299 strcpyW(uipath,file->TargetPath);
3300 *(strrchrW(uipath,'\\')+1)=0;
3301 MSI_RecordSetStringW(uirow,9,uipath);
3302 MSI_RecordSetInteger(uirow,6,file->FileSize);
3303 ui_actiondata(package,szInstallFiles,uirow);
3304 msiobj_release( &uirow->hdr );
3305 ui_progress(package,2,file->FileSize,0,0);
3307 if (!MoveFileW(file->SourcePath,file->TargetPath))
3309 rc = GetLastError();
3310 ERR("Unable to move file (%s -> %s) (error %d)\n",
3311 debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
3312 rc);
3313 if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
3315 CopyFileW(file->SourcePath,file->TargetPath,FALSE);
3316 DeleteFileW(file->SourcePath);
3317 rc = 0;
3319 else if (rc == ERROR_FILE_NOT_FOUND)
3321 ERR("Source File Not Found! Continueing\n");
3322 rc = 0;
3324 else
3326 ERR("Ignoring Error and continuing...\n");
3327 rc = 0;
3330 else
3331 file->State = 4;
3335 return rc;
3338 inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
3339 LPWSTR* file_source)
3341 DWORD index;
3343 if (!package)
3344 return ERROR_INVALID_HANDLE;
3346 for (index = 0; index < package->loaded_files; index ++)
3348 if (strcmpW(file_key,package->files[index].File)==0)
3350 if (package->files[index].State >= 2)
3352 *file_source = dupstrW(package->files[index].TargetPath);
3353 return ERROR_SUCCESS;
3355 else
3356 return ERROR_FILE_NOT_FOUND;
3360 return ERROR_FUNCTION_FAILED;
3363 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
3365 UINT rc;
3366 MSIQUERY * view;
3367 MSIRECORD * row = 0;
3368 static const WCHAR ExecSeqQuery[] = {
3369 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
3370 'D','u','p','l','i','c','a','t','e','F','i','l','e',0};
3372 if (!package)
3373 return ERROR_INVALID_HANDLE;
3375 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3376 if (rc != ERROR_SUCCESS)
3377 return ERROR_SUCCESS;
3379 rc = MSI_ViewExecute(view, 0);
3380 if (rc != ERROR_SUCCESS)
3382 MSI_ViewClose(view);
3383 msiobj_release(&view->hdr);
3384 return rc;
3387 while (1)
3389 WCHAR file_key[0x100];
3390 WCHAR *file_source = NULL;
3391 WCHAR dest_name[0x100];
3392 LPWSTR dest_path, dest;
3393 WCHAR component[0x100];
3394 INT component_index;
3396 DWORD sz=0x100;
3398 rc = MSI_ViewFetch(view,&row);
3399 if (rc != ERROR_SUCCESS)
3401 rc = ERROR_SUCCESS;
3402 break;
3405 sz=0x100;
3406 rc = MSI_RecordGetStringW(row,2,component,&sz);
3407 if (rc != ERROR_SUCCESS)
3409 ERR("Unable to get component\n");
3410 msiobj_release(&row->hdr);
3411 break;
3414 component_index = get_loaded_component(package,component);
3415 if (package->components[component_index].ActionRequest !=
3416 INSTALLSTATE_LOCAL)
3418 TRACE("Skipping copy due to disabled component\n");
3419 msiobj_release(&row->hdr);
3420 continue;
3423 sz=0x100;
3424 rc = MSI_RecordGetStringW(row,3,file_key,&sz);
3425 if (rc != ERROR_SUCCESS)
3427 ERR("Unable to get file key\n");
3428 msiobj_release(&row->hdr);
3429 break;
3432 rc = get_file_target(package,file_key,&file_source);
3434 if (rc != ERROR_SUCCESS)
3436 ERR("Original file unknown %s\n",debugstr_w(file_key));
3437 msiobj_release(&row->hdr);
3438 HeapFree(GetProcessHeap(),0,file_source);
3439 continue;
3442 if (MSI_RecordIsNull(row,4))
3444 strcpyW(dest_name,strrchrW(file_source,'\\')+1);
3446 else
3448 sz=0x100;
3449 MSI_RecordGetStringW(row,4,dest_name,&sz);
3450 reduce_to_longfilename(dest_name);
3453 if (MSI_RecordIsNull(row,5))
3455 LPWSTR p;
3456 dest_path = dupstrW(file_source);
3457 p = strrchrW(dest_path,'\\');
3458 if (p)
3459 *p=0;
3461 else
3463 WCHAR destkey[0x100];
3464 sz=0x100;
3465 MSI_RecordGetStringW(row,5,destkey,&sz);
3466 sz = 0x100;
3467 dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
3468 if (!dest_path)
3470 ERR("Unable to get destination folder\n");
3471 msiobj_release(&row->hdr);
3472 HeapFree(GetProcessHeap(),0,file_source);
3473 break;
3477 dest = build_directory_name(2, dest_path, dest_name);
3478 HeapFree(GetProcessHeap(), 0, dest_path);
3480 TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
3481 debugstr_w(dest));
3483 if (strcmpW(file_source,dest))
3484 rc = !CopyFileW(file_source,dest,TRUE);
3485 else
3486 rc = ERROR_SUCCESS;
3488 if (rc != ERROR_SUCCESS)
3489 ERR("Failed to copy file\n");
3491 FIXME("We should track these duplicate files as well\n");
3493 msiobj_release(&row->hdr);
3494 HeapFree(GetProcessHeap(),0,dest);
3495 HeapFree(GetProcessHeap(),0,file_source);
3497 MSI_ViewClose(view);
3498 msiobj_release(&view->hdr);
3499 return rc;
3503 /* OK this value is "interpretted" and then formatted based on the
3504 first few characters */
3505 static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type,
3506 DWORD *size)
3508 LPSTR data = NULL;
3509 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
3511 if (value[1]=='x')
3513 LPWSTR ptr;
3514 CHAR byte[5];
3515 LPWSTR deformated;
3516 int count;
3518 deformat_string(package, &value[2], &deformated);
3520 /* binary value type */
3521 ptr = deformated;
3522 *type=REG_BINARY;
3523 *size = strlenW(ptr)/2;
3524 data = HeapAlloc(GetProcessHeap(),0,*size);
3526 byte[0] = '0';
3527 byte[1] = 'x';
3528 byte[4] = 0;
3529 count = 0;
3530 while (*ptr)
3532 byte[2]= *ptr;
3533 ptr++;
3534 byte[3]= *ptr;
3535 ptr++;
3536 data[count] = (BYTE)strtol(byte,NULL,0);
3537 count ++;
3539 HeapFree(GetProcessHeap(),0,deformated);
3541 TRACE("Data %li bytes(%i)\n",*size,count);
3543 else
3545 LPWSTR deformated;
3546 deformat_string(package, &value[1], &deformated);
3548 *type=REG_DWORD;
3549 *size = sizeof(DWORD);
3550 data = HeapAlloc(GetProcessHeap(),0,*size);
3551 *(LPDWORD)data = atoiW(deformated);
3552 TRACE("DWORD %i\n",*data);
3554 HeapFree(GetProcessHeap(),0,deformated);
3557 else
3559 WCHAR *ptr;
3560 *type=REG_SZ;
3562 if (value[0]=='#')
3564 if (value[1]=='%')
3566 ptr = &value[2];
3567 *type=REG_EXPAND_SZ;
3569 else
3570 ptr = &value[1];
3572 else
3573 ptr=value;
3575 *size = deformat_string(package, ptr,(LPWSTR*)&data);
3577 return data;
3580 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
3582 UINT rc;
3583 MSIQUERY * view;
3584 MSIRECORD * row = 0;
3585 static const WCHAR ExecSeqQuery[] = {
3586 's','e','l','e','c','t',' ','*',' ',
3587 'f','r','o','m',' ','R','e','g','i','s','t','r','y',0 };
3589 if (!package)
3590 return ERROR_INVALID_HANDLE;
3592 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3593 if (rc != ERROR_SUCCESS)
3594 return ERROR_SUCCESS;
3596 rc = MSI_ViewExecute(view, 0);
3597 if (rc != ERROR_SUCCESS)
3599 MSI_ViewClose(view);
3600 msiobj_release(&view->hdr);
3601 return rc;
3604 /* increment progress bar each time action data is sent */
3605 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
3607 while (1)
3609 static const WCHAR szHCR[] =
3610 {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T','\\',0};
3611 static const WCHAR szHCU[] =
3612 {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',0};
3613 static const WCHAR szHLM[] =
3614 {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',
3615 '\\',0};
3616 static const WCHAR szHU[] =
3617 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
3619 LPSTR value_data = NULL;
3620 HKEY root_key, hkey;
3621 DWORD type,size;
3622 LPWSTR value, key, name, component, deformated;
3623 LPCWSTR szRoot;
3624 INT component_index;
3625 MSIRECORD * uirow;
3626 LPWSTR uikey;
3627 INT root;
3629 rc = MSI_ViewFetch(view,&row);
3630 if (rc != ERROR_SUCCESS)
3632 rc = ERROR_SUCCESS;
3633 break;
3635 ui_progress(package,2,0,0,0);
3637 value = NULL;
3638 key = NULL;
3639 uikey = NULL;
3640 name = NULL;
3642 component = load_dynamic_stringW(row, 6);
3643 component_index = get_loaded_component(package,component);
3645 if (package->components[component_index].ActionRequest !=
3646 INSTALLSTATE_LOCAL)
3648 TRACE("Skipping write due to disabled component\n");
3649 msiobj_release(&row->hdr);
3650 goto next;
3653 /* null values have special meanings during uninstalls and such */
3655 if(MSI_RecordIsNull(row,5))
3657 msiobj_release(&row->hdr);
3658 goto next;
3661 root = MSI_RecordGetInteger(row,2);
3662 key = load_dynamic_stringW(row, 3);
3664 name = load_dynamic_stringW(row, 4);
3666 /* get the root key */
3667 switch (root)
3669 case 0: root_key = HKEY_CLASSES_ROOT;
3670 szRoot = szHCR;
3671 break;
3672 case 1: root_key = HKEY_CURRENT_USER;
3673 szRoot = szHCU;
3674 break;
3675 case 2: root_key = HKEY_LOCAL_MACHINE;
3676 szRoot = szHLM;
3677 break;
3678 case 3: root_key = HKEY_USERS;
3679 szRoot = szHU;
3680 break;
3681 default:
3682 ERR("Unknown root %i\n",root);
3683 root_key=NULL;
3684 szRoot = NULL;
3685 break;
3687 if (!root_key)
3689 msiobj_release(&row->hdr);
3690 goto next;
3693 deformat_string(package, key , &deformated);
3694 size = strlenW(deformated) + strlenW(szRoot) + 1;
3695 uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
3696 strcpyW(uikey,szRoot);
3697 strcatW(uikey,deformated);
3699 if (RegCreateKeyW( root_key, deformated, &hkey))
3701 ERR("Could not create key %s\n",debugstr_w(deformated));
3702 msiobj_release(&row->hdr);
3703 HeapFree(GetProcessHeap(),0,deformated);
3704 goto next;
3706 HeapFree(GetProcessHeap(),0,deformated);
3708 value = load_dynamic_stringW(row,5);
3709 value_data = parse_value(package, value, &type, &size);
3711 deformat_string(package, name, &deformated);
3713 if (value_data)
3715 TRACE("Setting value %s\n",debugstr_w(deformated));
3716 RegSetValueExW(hkey, deformated, 0, type, value_data, size);
3718 uirow = MSI_CreateRecord(3);
3719 MSI_RecordSetStringW(uirow,2,deformated);
3720 MSI_RecordSetStringW(uirow,1,uikey);
3722 if (type == REG_SZ)
3723 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
3724 else
3725 MSI_RecordSetStringW(uirow,3,value);
3727 ui_actiondata(package,szWriteRegistryValues,uirow);
3728 msiobj_release( &uirow->hdr );
3730 HeapFree(GetProcessHeap(),0,value_data);
3732 HeapFree(GetProcessHeap(),0,value);
3733 HeapFree(GetProcessHeap(),0,deformated);
3735 msiobj_release(&row->hdr);
3736 RegCloseKey(hkey);
3737 next:
3738 HeapFree(GetProcessHeap(),0,uikey);
3739 HeapFree(GetProcessHeap(),0,key);
3740 HeapFree(GetProcessHeap(),0,name);
3741 HeapFree(GetProcessHeap(),0,component);
3743 MSI_ViewClose(view);
3744 msiobj_release(&view->hdr);
3745 return rc;
3749 * This helper function should probably go alot of places
3751 * Thinking about this, maybe this should become yet another Bison file
3753 static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data)
3755 WCHAR* mark=NULL;
3756 WCHAR* mark2;
3757 DWORD size=0;
3758 DWORD chunk=0;
3759 WCHAR key[0x100];
3760 LPWSTR value = NULL;
3761 DWORD sz;
3762 UINT rc;
3763 INT index;
3765 if (ptr==NULL)
3767 TRACE("Deformatting NULL string\n");
3768 *data = NULL;
3769 return 0;
3771 TRACE("Starting with %s\n",debugstr_w(ptr));
3772 /* scan for special characters */
3773 if (!strchrW(ptr,'[') || (strchrW(ptr,'[') && !strchrW(ptr,']')))
3775 /* not formatted */
3776 size = (strlenW(ptr)+1) * sizeof(WCHAR);
3777 *data = HeapAlloc(GetProcessHeap(),0,size);
3778 strcpyW(*data,ptr);
3779 return size;
3782 /* formatted string located */
3783 mark = strchrW(ptr,'[');
3784 if (mark != ptr)
3786 INT cnt = (mark - ptr);
3787 TRACE("%i (%i) characters before marker\n",cnt,(mark-ptr));
3788 size = cnt * sizeof(WCHAR);
3789 size += sizeof(WCHAR);
3790 *data = HeapAlloc(GetProcessHeap(),0,size);
3791 strncpyW(*data,ptr,cnt);
3792 (*data)[cnt]=0;
3794 else
3796 size = sizeof(WCHAR);
3797 *data = HeapAlloc(GetProcessHeap(),0,size);
3798 (*data)[0]=0;
3800 mark++;
3801 mark2 = strchrW(mark,']');
3802 strncpyW(key,mark,mark2-mark);
3803 key[mark2-mark] = 0;
3804 mark = strchrW(mark,']');
3805 mark++;
3806 TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
3807 sz = 0;
3808 /* expand what we can deformat... Again, this should become a bison file */
3809 switch (key[0])
3811 case '~':
3812 ERR("UNHANDLED DEFORMAT.. [~] should be NULL\n");
3813 rc = ERROR_FUNCTION_FAILED;
3814 break;
3815 case '$':
3816 ERR("POORLY HANDLED DEFORMAT.. [$componentkey] \n");
3817 index = get_loaded_component(package,&key[1]);
3818 if (index >= 0)
3820 value = resolve_folder(package,
3821 package->components[index].Directory,
3822 FALSE, FALSE, NULL);
3823 rc = 0;
3825 else
3826 rc = ERROR_FUNCTION_FAILED;
3827 break;
3828 case '#':
3829 index = get_loaded_file(package,&key[1]);
3830 if (index >=0)
3832 sz = strlenW(package->files[index].TargetPath);
3833 value = dupstrW(package->files[index].TargetPath);
3834 rc= ERROR_SUCCESS;
3836 else
3837 rc = ERROR_FUNCTION_FAILED;
3838 break;
3839 case '\\':
3840 value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2);
3841 value[0] = key[1];
3842 rc = ERROR_SUCCESS;
3843 break;
3844 case '%':
3845 sz = GetEnvironmentVariableW(&key[1],NULL,0);
3846 sz++;
3847 value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
3848 GetEnvironmentVariableW(&key[1],value,sz);
3849 rc = ERROR_SUCCESS;
3850 break;
3851 default:
3852 rc = MSI_GetPropertyW(package, key, NULL, &sz);
3853 sz++;
3854 value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
3855 MSI_GetPropertyW(package, key, value, &sz);
3856 break;
3858 if (((rc == ERROR_SUCCESS) || (rc == ERROR_MORE_DATA))&& value!=NULL)
3860 LPWSTR newdata;
3862 chunk = (strlenW(value)+1) * sizeof(WCHAR);
3863 size+=chunk;
3864 newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
3865 *data = newdata;
3866 strcatW(*data,value);
3868 TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
3869 if (*mark!=0)
3871 LPWSTR newdata;
3872 chunk = (strlenW(mark)+1) * sizeof(WCHAR);
3873 size+=chunk;
3874 newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
3875 *data = newdata;
3876 strcatW(*data,mark);
3878 (*data)[strlenW(*data)]=0;
3879 TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
3881 /* recursively do this to clean up */
3882 mark = HeapAlloc(GetProcessHeap(),0,size);
3883 strcpyW(mark,*data);
3884 TRACE("String at this point %s\n",debugstr_w(mark));
3885 size = deformat_string(package,mark,data);
3886 HeapFree(GetProcessHeap(),0,mark);
3887 return size;
3890 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3892 return ERROR_SUCCESS;
3896 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3898 DWORD progress = 0;
3899 DWORD total = 0;
3900 static const WCHAR q1[]={
3901 'S','E','L','E','C','T',' ','*',' ',
3902 'F','R','O','M',' ','R','e','g','i','s','t','r','y',0};
3903 UINT rc;
3904 MSIQUERY * view;
3905 MSIRECORD * row = 0;
3906 int i;
3908 TRACE(" InstallValidate \n");
3910 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3911 if (rc != ERROR_SUCCESS)
3912 return ERROR_SUCCESS;
3914 rc = MSI_ViewExecute(view, 0);
3915 if (rc != ERROR_SUCCESS)
3917 MSI_ViewClose(view);
3918 msiobj_release(&view->hdr);
3919 return rc;
3921 while (1)
3923 rc = MSI_ViewFetch(view,&row);
3924 if (rc != ERROR_SUCCESS)
3926 rc = ERROR_SUCCESS;
3927 break;
3929 progress +=1;
3931 msiobj_release(&row->hdr);
3933 MSI_ViewClose(view);
3934 msiobj_release(&view->hdr);
3936 total = total + progress * REG_PROGRESS_VALUE;
3937 total = total + package->loaded_components * COMPONENT_PROGRESS_VALUE;
3938 for (i=0; i < package->loaded_files; i++)
3939 total += package->files[i].FileSize;
3940 ui_progress(package,0,total,0,0);
3942 return ERROR_SUCCESS;
3945 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3947 UINT rc;
3948 MSIQUERY * view = NULL;
3949 MSIRECORD * row = 0;
3950 static const WCHAR ExecSeqQuery[] = {
3951 'S','E','L','E','C','T',' ','*',' ',
3952 'f','r','o','m',' ','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n',0};
3953 static const WCHAR title[]=
3954 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3956 TRACE("Checking launch conditions\n");
3958 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3959 if (rc != ERROR_SUCCESS)
3960 return ERROR_SUCCESS;
3962 rc = MSI_ViewExecute(view, 0);
3963 if (rc != ERROR_SUCCESS)
3965 MSI_ViewClose(view);
3966 msiobj_release(&view->hdr);
3967 return rc;
3970 rc = ERROR_SUCCESS;
3971 while (rc == ERROR_SUCCESS)
3973 LPWSTR cond = NULL;
3974 LPWSTR message = NULL;
3976 rc = MSI_ViewFetch(view,&row);
3977 if (rc != ERROR_SUCCESS)
3979 rc = ERROR_SUCCESS;
3980 break;
3983 cond = load_dynamic_stringW(row,1);
3985 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
3987 LPWSTR deformated;
3988 message = load_dynamic_stringW(row,2);
3989 deformat_string(package,message,&deformated);
3990 MessageBoxW(NULL,deformated,title,MB_OK);
3991 HeapFree(GetProcessHeap(),0,message);
3992 HeapFree(GetProcessHeap(),0,deformated);
3993 rc = ERROR_FUNCTION_FAILED;
3995 HeapFree(GetProcessHeap(),0,cond);
3996 msiobj_release(&row->hdr);
3998 MSI_ViewClose(view);
3999 msiobj_release(&view->hdr);
4000 return rc;
4003 static LPWSTR resolve_keypath( MSIPACKAGE* package, INT
4004 component_index)
4006 MSICOMPONENT* cmp = &package->components[component_index];
4008 if (cmp->KeyPath[0]==0)
4010 LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
4011 return p;
4013 if (cmp->Attributes & 0x4)
4015 MSIQUERY * view;
4016 MSIRECORD * row = 0;
4017 UINT rc,root,len;
4018 LPWSTR key,deformated,buffer,name,deformated_name;
4019 static const WCHAR ExecSeqQuery[] = {
4020 's','e','l','e','c','t',' ','*',' ',
4021 'f','r','o','m',' ','R','e','g','i','s','t','r','y',' ',
4022 'w','h','e','r','e',' ','R','e','g','i','s','t','r','y',' ','=',' '
4023 ,'`','%','s','`',0 };
4024 static const WCHAR fmt[]={'%','0','2','i',':','%','s',0};
4025 static const WCHAR fmt2[]={'%','0','2','i',':','%','s','\\','%','s',0};
4027 rc = MSI_OpenQuery(package->db,&view,ExecSeqQuery,cmp->KeyPath);
4029 if (rc!=ERROR_SUCCESS)
4030 return NULL;
4032 rc = MSI_ViewExecute(view, 0);
4033 if (rc != ERROR_SUCCESS)
4035 MSI_ViewClose(view);
4036 msiobj_release(&view->hdr);
4037 return NULL;
4040 rc = MSI_ViewFetch(view,&row);
4041 if (rc != ERROR_SUCCESS)
4043 MSI_ViewClose(view);
4044 msiobj_release(&view->hdr);
4045 return NULL;
4048 root = MSI_RecordGetInteger(row,2);
4049 key = load_dynamic_stringW(row, 3);
4050 name = load_dynamic_stringW(row, 4);
4051 deformat_string(package, key , &deformated);
4052 deformat_string(package, name, &deformated_name);
4054 len = strlenW(deformated) + 5;
4055 if (deformated_name)
4056 len+=strlenW(deformated_name);
4058 buffer = HeapAlloc(GetProcessHeap(),0, len *sizeof(WCHAR));
4060 if (deformated_name)
4061 sprintfW(buffer,fmt2,root,deformated,deformated_name);
4062 else
4063 sprintfW(buffer,fmt,root,deformated);
4065 HeapFree(GetProcessHeap(),0,key);
4066 HeapFree(GetProcessHeap(),0,deformated);
4067 HeapFree(GetProcessHeap(),0,name);
4068 HeapFree(GetProcessHeap(),0,deformated_name);
4069 msiobj_release(&row->hdr);
4070 MSI_ViewClose(view);
4071 msiobj_release(&view->hdr);
4073 return buffer;
4075 else if (cmp->Attributes & 0x20)
4077 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
4078 return NULL;
4080 else
4082 int j;
4083 j = get_loaded_file(package,cmp->KeyPath);
4085 if (j>=0)
4087 LPWSTR p = dupstrW(package->files[j].TargetPath);
4088 return p;
4091 return NULL;
4095 * Ok further analysis makes me think that this work is
4096 * actually done in the PublishComponents and PublishFeatures
4097 * step, and not here. It appears like the keypath and all that is
4098 * resolved in this step, however actually written in the Publish steps.
4099 * But we will leave it here for now because it is unclear
4101 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
4103 LPWSTR productcode;
4104 WCHAR squished_pc[GUID_SIZE];
4105 WCHAR squished_cc[GUID_SIZE];
4106 UINT rc;
4107 DWORD i;
4108 HKEY hkey=0,hkey2=0;
4109 static const WCHAR szProductCode[]=
4110 {'P','r','o','d','u','c','t','C','o','d','e',0};
4112 if (!package)
4113 return ERROR_INVALID_HANDLE;
4115 /* writes the Component and Features values to the registry */
4116 productcode = load_dynamic_property(package,szProductCode,&rc);
4117 if (!productcode)
4118 return rc;
4120 rc = MSIREG_OpenComponents(&hkey);
4121 if (rc != ERROR_SUCCESS)
4122 goto end;
4124 squash_guid(productcode,squished_pc);
4125 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
4126 for (i = 0; i < package->loaded_components; i++)
4128 ui_progress(package,2,0,0,0);
4129 if (package->components[i].ComponentId[0]!=0)
4131 WCHAR *keypath = NULL;
4132 MSIRECORD * uirow;
4134 squash_guid(package->components[i].ComponentId,squished_cc);
4135 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
4136 if (rc != ERROR_SUCCESS)
4137 continue;
4139 keypath = resolve_keypath(package,i);
4140 if (keypath)
4142 RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath,
4143 (strlenW(keypath)+1)*sizeof(WCHAR));
4144 RegCloseKey(hkey2);
4146 /* UI stuff */
4147 uirow = MSI_CreateRecord(3);
4148 MSI_RecordSetStringW(uirow,1,productcode);
4149 MSI_RecordSetStringW(uirow,2,package->components[i].
4150 ComponentId);
4151 MSI_RecordSetStringW(uirow,3,keypath);
4152 ui_actiondata(package,szProcessComponents,uirow);
4153 msiobj_release( &uirow->hdr );
4154 HeapFree(GetProcessHeap(),0,keypath);
4158 end:
4159 HeapFree(GetProcessHeap(), 0, productcode);
4160 RegCloseKey(hkey);
4161 return rc;
4164 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
4167 * OK this is a bit confusing.. I am given a _Component key and I believe
4168 * that the file that is being registered as a type library is the "key file
4169 * of that component" which I interpret to mean "The file in the KeyPath of
4170 * that component".
4172 UINT rc;
4173 MSIQUERY * view;
4174 MSIRECORD * row = 0;
4175 static const WCHAR Query[] = {
4176 'S','E','L','E','C','T',' ','*',' ',
4177 'f','r','o','m',' ','T','y','p','e','L','i','b',0};
4178 ITypeLib *ptLib;
4179 HRESULT res;
4181 if (!package)
4182 return ERROR_INVALID_HANDLE;
4184 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4185 if (rc != ERROR_SUCCESS)
4186 return ERROR_SUCCESS;
4188 rc = MSI_ViewExecute(view, 0);
4189 if (rc != ERROR_SUCCESS)
4191 MSI_ViewClose(view);
4192 msiobj_release(&view->hdr);
4193 return rc;
4196 while (1)
4198 WCHAR component[0x100];
4199 DWORD sz;
4200 INT index;
4202 rc = MSI_ViewFetch(view,&row);
4203 if (rc != ERROR_SUCCESS)
4205 rc = ERROR_SUCCESS;
4206 break;
4209 sz = 0x100;
4210 MSI_RecordGetStringW(row,3,component,&sz);
4212 index = get_loaded_component(package,component);
4213 if (index < 0)
4215 msiobj_release(&row->hdr);
4216 continue;
4219 if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
4221 TRACE("Skipping typelib reg due to disabled component\n");
4222 msiobj_release(&row->hdr);
4223 continue;
4226 index = get_loaded_file(package,package->components[index].KeyPath);
4228 if (index < 0)
4230 msiobj_release(&row->hdr);
4231 continue;
4234 res = LoadTypeLib(package->files[index].TargetPath,&ptLib);
4235 if (SUCCEEDED(res))
4237 LPWSTR help;
4238 WCHAR helpid[0x100];
4240 sz = 0x100;
4241 MSI_RecordGetStringW(row,6,helpid,&sz);
4243 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
4244 res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help);
4245 HeapFree(GetProcessHeap(),0,help);
4247 if (!SUCCEEDED(res))
4248 ERR("Failed to register type library %s\n",
4249 debugstr_w(package->files[index].TargetPath));
4250 else
4252 /* Yes the row has more fields than I need, but #1 is
4253 correct and the only one I need. Why make a new row? */
4255 ui_actiondata(package,szRegisterTypeLibraries,row);
4257 TRACE("Registered %s\n",
4258 debugstr_w(package->files[index].TargetPath));
4261 if (ptLib)
4262 ITypeLib_Release(ptLib);
4264 else
4265 ERR("Failed to load type library %s\n",
4266 debugstr_w(package->files[index].TargetPath));
4268 msiobj_release(&row->hdr);
4270 MSI_ViewClose(view);
4271 msiobj_release(&view->hdr);
4272 return rc;
4276 static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
4278 static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
4279 UINT rc;
4280 MSIQUERY * view;
4281 MSIRECORD * row = 0;
4282 static const WCHAR ExecSeqQuery[] =
4283 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'
4284 ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};
4285 HKEY hkey2,hkey3;
4286 LPWSTR buffer=0;
4288 if (!package)
4289 return ERROR_INVALID_HANDLE;
4291 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, clsid);
4292 if (rc != ERROR_SUCCESS)
4293 return rc;
4295 rc = MSI_ViewExecute(view, 0);
4296 if (rc != ERROR_SUCCESS)
4298 MSI_ViewClose(view);
4299 msiobj_release(&view->hdr);
4300 return rc;
4303 RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
4304 RegCreateKeyW(hkey2,clsid,&hkey3);
4305 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
4306 (strlenW(app)+1)*sizeof(WCHAR));
4308 rc = MSI_ViewFetch(view,&row);
4309 if (rc != ERROR_SUCCESS)
4311 MSI_ViewClose(view);
4312 msiobj_release(&view->hdr);
4313 return rc;
4316 if (!MSI_RecordIsNull(row,2))
4318 LPWSTR deformated=0;
4319 UINT size;
4320 static const WCHAR szRemoteServerName[] =
4321 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
4322 buffer = load_dynamic_stringW(row,2);
4323 size = deformat_string(package,buffer,&deformated);
4324 RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated,
4325 size);
4326 HeapFree(GetProcessHeap(),0,deformated);
4327 HeapFree(GetProcessHeap(),0,buffer);
4330 if (!MSI_RecordIsNull(row,3))
4332 static const WCHAR szLocalService[] =
4333 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
4334 UINT size;
4335 buffer = load_dynamic_stringW(row,3);
4336 size = (strlenW(buffer)+1) * sizeof(WCHAR);
4337 RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size);
4338 HeapFree(GetProcessHeap(),0,buffer);
4341 if (!MSI_RecordIsNull(row,4))
4343 static const WCHAR szService[] =
4344 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
4345 UINT size;
4346 buffer = load_dynamic_stringW(row,4);
4347 size = (strlenW(buffer)+1) * sizeof(WCHAR);
4348 RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size);
4349 HeapFree(GetProcessHeap(),0,buffer);
4352 if (!MSI_RecordIsNull(row,5))
4354 static const WCHAR szDLL[] =
4355 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
4356 UINT size;
4357 buffer = load_dynamic_stringW(row,5);
4358 size = (strlenW(buffer)+1) * sizeof(WCHAR);
4359 RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size);
4360 HeapFree(GetProcessHeap(),0,buffer);
4363 if (!MSI_RecordIsNull(row,6))
4365 static const WCHAR szActivate[] =
4366 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
4367 static const WCHAR szY[] = {'Y',0};
4369 if (MSI_RecordGetInteger(row,6))
4370 RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
4373 if (!MSI_RecordIsNull(row,7))
4375 static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
4376 static const WCHAR szUser[] =
4377 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
4379 if (MSI_RecordGetInteger(row,7))
4380 RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34);
4383 msiobj_release(&row->hdr);
4384 MSI_ViewClose(view);
4385 msiobj_release(&view->hdr);
4386 RegCloseKey(hkey3);
4387 RegCloseKey(hkey2);
4388 return rc;
4391 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
4394 * Again I am assuming the words, "Whose key file represents" when referring
4395 * to a Component as to meaning that Components KeyPath file
4397 * Also there is a very strong connection between ClassInfo and ProgID
4398 * that I am mostly glossing over.
4399 * What would be more propper is to load the ClassInfo and the ProgID info
4400 * into memory data structures and then be able to enable and disable them
4401 * based on component.
4404 UINT rc;
4405 MSIQUERY * view;
4406 MSIRECORD * row = 0;
4407 static const WCHAR ExecSeqQuery[] = {
4408 'S','E','L','E','C','T',' ','*',' ',
4409 'f','r','o','m',' ','C','l','a','s','s',0};
4410 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
4411 static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
4412 static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
4413 HKEY hkey,hkey2,hkey3;
4415 if (!package)
4416 return ERROR_INVALID_HANDLE;
4418 rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
4419 if (rc != ERROR_SUCCESS)
4420 return ERROR_FUNCTION_FAILED;
4422 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4423 if (rc != ERROR_SUCCESS)
4425 rc = ERROR_SUCCESS;
4426 goto end;
4429 rc = MSI_ViewExecute(view, 0);
4430 if (rc != ERROR_SUCCESS)
4432 MSI_ViewClose(view);
4433 msiobj_release(&view->hdr);
4434 goto end;
4437 while (1)
4439 WCHAR clsid[0x100];
4440 WCHAR buffer[0x100];
4441 WCHAR desc[0x100];
4442 DWORD sz;
4443 INT index;
4445 rc = MSI_ViewFetch(view,&row);
4446 if (rc != ERROR_SUCCESS)
4448 rc = ERROR_SUCCESS;
4449 break;
4452 sz=0x100;
4453 MSI_RecordGetStringW(row,3,buffer,&sz);
4455 index = get_loaded_component(package,buffer);
4457 if (index < 0)
4459 msiobj_release(&row->hdr);
4460 continue;
4463 if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
4465 TRACE("Skipping class reg due to disabled component\n");
4466 msiobj_release(&row->hdr);
4467 continue;
4470 sz=0x100;
4471 MSI_RecordGetStringW(row,1,clsid,&sz);
4472 RegCreateKeyW(hkey,clsid,&hkey2);
4474 if (!MSI_RecordIsNull(row,5))
4476 sz=0x100;
4477 MSI_RecordGetStringW(row,5,desc,&sz);
4479 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc,
4480 (strlenW(desc)+1)*sizeof(WCHAR));
4482 else
4483 desc[0]=0;
4485 sz=0x100;
4486 MSI_RecordGetStringW(row,2,buffer,&sz);
4488 RegCreateKeyW(hkey2,buffer,&hkey3);
4490 index = get_loaded_file(package,package->components[index].KeyPath);
4491 RegSetValueExW(hkey3,NULL,0,REG_SZ,
4492 (LPVOID)package->files[index].TargetPath,
4493 (strlenW(package->files[index].TargetPath)+1)
4494 *sizeof(WCHAR));
4496 RegCloseKey(hkey3);
4498 if (!MSI_RecordIsNull(row,4))
4500 sz=0x100;
4501 MSI_RecordGetStringW(row,4,buffer,&sz);
4503 RegCreateKeyW(hkey2,szProgID,&hkey3);
4505 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer,
4506 (strlenW(buffer)+1)*sizeof(WCHAR));
4508 RegCloseKey(hkey3);
4511 if (!MSI_RecordIsNull(row,6))
4513 sz=0x100;
4514 MSI_RecordGetStringW(row,6,buffer,&sz);
4516 RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer,
4517 (strlenW(buffer)+1)*sizeof(WCHAR));
4519 register_appid(package,buffer,desc);
4522 RegCloseKey(hkey2);
4524 FIXME("Process the rest of the fields >7\n");
4526 ui_actiondata(package,szRegisterClassInfo,row);
4528 msiobj_release(&row->hdr);
4530 MSI_ViewClose(view);
4531 msiobj_release(&view->hdr);
4533 end:
4534 RegCloseKey(hkey);
4535 return rc;
4538 static UINT register_progid_base(MSIPACKAGE* package, MSIRECORD * row,
4539 LPWSTR clsid)
4541 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
4542 static const WCHAR szDefaultIcon[] = {
4543 'D','e','f','a','u','l','t','I','c','o','n',0};
4544 HKEY hkey,hkey2;
4545 WCHAR buffer[0x100];
4546 DWORD sz;
4549 sz = 0x100;
4550 MSI_RecordGetStringW(row,1,buffer,&sz);
4551 RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
4553 if (!MSI_RecordIsNull(row,4))
4555 sz = 0x100;
4556 MSI_RecordGetStringW(row,4,buffer,&sz);
4557 RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
4558 sizeof(WCHAR));
4561 if (!MSI_RecordIsNull(row,3))
4563 sz = 0x100;
4565 MSI_RecordGetStringW(row,3,buffer,&sz);
4566 RegCreateKeyW(hkey,szCLSID,&hkey2);
4567 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
4568 sizeof(WCHAR));
4570 if (clsid)
4571 strcpyW(clsid,buffer);
4573 RegCloseKey(hkey2);
4575 else
4577 FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
4578 return ERROR_FUNCTION_FAILED;
4580 if (!MSI_RecordIsNull(row,5))
4582 INT index = MSI_RecordGetInteger(row,6);
4583 LPWSTR FileName = load_dynamic_stringW(row,5);
4584 LPWSTR FilePath,IconPath;
4585 static const WCHAR fmt[] = {'%','s',',','%','i',0};
4587 RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
4588 build_icon_path(package,FileName,&FilePath);
4590 IconPath = HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)*
4591 sizeof(WCHAR));
4593 sprintfW(IconPath,fmt,FilePath,index);
4594 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)IconPath,
4595 (strlenW(IconPath)+1) * sizeof(WCHAR));
4596 HeapFree(GetProcessHeap(),0,FilePath);
4597 HeapFree(GetProcessHeap(),0,FileName);
4598 RegCloseKey(hkey2);
4600 return ERROR_SUCCESS;
4603 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid);
4605 static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent,
4606 LPWSTR clsid)
4608 UINT rc;
4609 MSIQUERY * view;
4610 MSIRECORD * row = 0;
4611 static const WCHAR Query_t[] =
4612 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'
4613 ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'
4614 ,'%','s','`',0};
4616 if (!package)
4617 return ERROR_INVALID_HANDLE;
4619 rc = MSI_OpenQuery(package->db, &view, Query_t, parent);
4620 if (rc != ERROR_SUCCESS)
4621 return rc;
4623 rc = MSI_ViewExecute(view, 0);
4624 if (rc != ERROR_SUCCESS)
4626 MSI_ViewClose(view);
4627 msiobj_release(&view->hdr);
4628 return rc;
4631 rc = MSI_ViewFetch(view,&row);
4632 if (rc != ERROR_SUCCESS)
4634 MSI_ViewClose(view);
4635 msiobj_release(&view->hdr);
4636 return rc;
4639 register_progid(package,row,clsid);
4641 msiobj_release(&row->hdr);
4642 MSI_ViewClose(view);
4643 msiobj_release(&view->hdr);
4644 return rc;
4647 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid)
4649 UINT rc = ERROR_SUCCESS;
4651 if (MSI_RecordIsNull(row,2))
4652 rc = register_progid_base(package,row,clsid);
4653 else
4655 WCHAR buffer[0x1000];
4656 DWORD sz, disp;
4657 HKEY hkey,hkey2;
4658 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
4659 static const WCHAR szDefaultIcon[] = {
4660 'D','e','f','a','u','l','t','I','c','o','n',0};
4662 /* check if already registered */
4663 sz = 0x100;
4664 MSI_RecordGetStringW(row,1,buffer,&sz);
4665 RegCreateKeyExW(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0,
4666 KEY_ALL_ACCESS, NULL, &hkey, &disp );
4667 if (disp == REG_OPENED_EXISTING_KEY)
4669 TRACE("Key already registered\n");
4670 RegCloseKey(hkey);
4671 return rc;
4674 sz = 0x100;
4675 MSI_RecordGetStringW(row,2,buffer,&sz);
4676 rc = register_parent_progid(package,buffer,clsid);
4678 /* clsid is same as parent */
4679 RegCreateKeyW(hkey,szCLSID,&hkey2);
4680 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
4681 sizeof(WCHAR));
4683 RegCloseKey(hkey2);
4686 if (!MSI_RecordIsNull(row,4))
4688 sz = 0x100;
4689 MSI_RecordGetStringW(row,4,buffer,&sz);
4690 RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer,
4691 (strlenW(buffer)+1) * sizeof(WCHAR));
4694 if (!MSI_RecordIsNull(row,5))
4696 LPWSTR FileName = load_dynamic_stringW(row,5);
4697 LPWSTR FilePath;
4698 RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
4699 build_icon_path(package,FileName,&FilePath);
4700 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)FilePath,
4701 (strlenW(FilePath)+1) * sizeof(WCHAR));
4702 HeapFree(GetProcessHeap(),0,FilePath);
4703 HeapFree(GetProcessHeap(),0,FileName);
4704 RegCloseKey(hkey2);
4707 RegCloseKey(hkey);
4709 return rc;
4712 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
4715 * Sigh, here I am just brute force registering all progids
4716 * this needs to be linked to the Classes that have been registered
4717 * but the easiest way to do that is to load all these stuff into
4718 * memory for easy checking.
4720 * Gives me something to continue to work toward.
4722 UINT rc;
4723 MSIQUERY * view;
4724 MSIRECORD * row = 0;
4725 static const WCHAR Query[] = {
4726 'S','E','L','E','C','T',' ','*',' ',
4727 'F','R','O','M',' ','P','r','o','g','I','d',0};
4729 if (!package)
4730 return ERROR_INVALID_HANDLE;
4732 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4733 if (rc != ERROR_SUCCESS)
4734 return ERROR_SUCCESS;
4736 rc = MSI_ViewExecute(view, 0);
4737 if (rc != ERROR_SUCCESS)
4739 MSI_ViewClose(view);
4740 msiobj_release(&view->hdr);
4741 return rc;
4744 while (1)
4746 WCHAR clsid[0x1000];
4748 rc = MSI_ViewFetch(view,&row);
4749 if (rc != ERROR_SUCCESS)
4751 rc = ERROR_SUCCESS;
4752 break;
4755 register_progid(package,row,clsid);
4756 ui_actiondata(package,szRegisterProgIdInfo,row);
4758 msiobj_release(&row->hdr);
4760 MSI_ViewClose(view);
4761 msiobj_release(&view->hdr);
4762 return rc;
4765 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name,
4766 LPWSTR *FilePath)
4768 LPWSTR ProductCode;
4769 LPWSTR SystemFolder;
4770 LPWSTR dest;
4771 UINT rc;
4773 static const WCHAR szInstaller[] =
4774 {'I','n','s','t','a','l','l','e','r','\\',0};
4775 static const WCHAR szProductCode[] =
4776 {'P','r','o','d','u','c','t','C','o','d','e',0};
4777 static const WCHAR szFolder[] =
4778 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
4780 ProductCode = load_dynamic_property(package,szProductCode,&rc);
4781 if (!ProductCode)
4782 return rc;
4784 SystemFolder = load_dynamic_property(package,szFolder,NULL);
4786 dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);
4788 create_full_pathW(dest);
4790 *FilePath = build_directory_name(2, dest, icon_name);
4792 HeapFree(GetProcessHeap(),0,SystemFolder);
4793 HeapFree(GetProcessHeap(),0,ProductCode);
4794 HeapFree(GetProcessHeap(),0,dest);
4795 return ERROR_SUCCESS;
4798 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
4800 UINT rc;
4801 MSIQUERY * view;
4802 MSIRECORD * row = 0;
4803 static const WCHAR Query[] = {
4804 'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ',
4805 'S','h','o','r','t','c','u','t',0};
4806 IShellLinkW *sl;
4807 IPersistFile *pf;
4808 HRESULT res;
4810 if (!package)
4811 return ERROR_INVALID_HANDLE;
4813 res = CoInitialize( NULL );
4814 if (FAILED (res))
4816 ERR("CoInitialize failed\n");
4817 return ERROR_FUNCTION_FAILED;
4820 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4821 if (rc != ERROR_SUCCESS)
4822 return ERROR_SUCCESS;
4824 rc = MSI_ViewExecute(view, 0);
4825 if (rc != ERROR_SUCCESS)
4827 MSI_ViewClose(view);
4828 msiobj_release(&view->hdr);
4829 return rc;
4832 while (1)
4834 LPWSTR target_file, target_folder;
4835 WCHAR buffer[0x100];
4836 DWORD sz;
4837 DWORD index;
4838 static const WCHAR szlnk[]={'.','l','n','k',0};
4840 rc = MSI_ViewFetch(view,&row);
4841 if (rc != ERROR_SUCCESS)
4843 rc = ERROR_SUCCESS;
4844 break;
4847 sz = 0x100;
4848 MSI_RecordGetStringW(row,4,buffer,&sz);
4850 index = get_loaded_component(package,buffer);
4852 if (index < 0)
4854 msiobj_release(&row->hdr);
4855 continue;
4858 if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
4860 TRACE("Skipping shortcut creation due to disabled component\n");
4861 msiobj_release(&row->hdr);
4862 continue;
4865 ui_actiondata(package,szCreateShortcuts,row);
4867 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
4868 &IID_IShellLinkW, (LPVOID *) &sl );
4870 if (FAILED(res))
4872 ERR("Is IID_IShellLink\n");
4873 msiobj_release(&row->hdr);
4874 continue;
4877 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
4878 if( FAILED( res ) )
4880 ERR("Is IID_IPersistFile\n");
4881 msiobj_release(&row->hdr);
4882 continue;
4885 sz = 0x100;
4886 MSI_RecordGetStringW(row,2,buffer,&sz);
4887 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
4889 /* may be needed because of a bug somehwere else */
4890 create_full_pathW(target_folder);
4892 sz = 0x100;
4893 MSI_RecordGetStringW(row,3,buffer,&sz);
4894 reduce_to_longfilename(buffer);
4895 if (!strchrW(buffer,'.') || strcmpiW(strchrW(buffer,'.'),szlnk))
4896 strcatW(buffer,szlnk);
4897 target_file = build_directory_name(2, target_folder, buffer);
4898 HeapFree(GetProcessHeap(),0,target_folder);
4900 sz = 0x100;
4901 MSI_RecordGetStringW(row,5,buffer,&sz);
4902 if (strchrW(buffer,'['))
4904 LPWSTR deformated;
4905 deformat_string(package,buffer,&deformated);
4906 IShellLinkW_SetPath(sl,deformated);
4907 HeapFree(GetProcessHeap(),0,deformated);
4909 else
4911 FIXME("UNHANDLED shortcut format, advertised shortcut\n");
4912 IPersistFile_Release( pf );
4913 IShellLinkW_Release( sl );
4914 msiobj_release(&row->hdr);
4915 continue;
4918 if (!MSI_RecordIsNull(row,6))
4920 LPWSTR deformated;
4921 sz = 0x100;
4922 MSI_RecordGetStringW(row,6,buffer,&sz);
4923 deformat_string(package,buffer,&deformated);
4924 IShellLinkW_SetArguments(sl,deformated);
4925 HeapFree(GetProcessHeap(),0,deformated);
4928 if (!MSI_RecordIsNull(row,7))
4930 LPWSTR deformated;
4931 deformated = load_dynamic_stringW(row,7);
4932 IShellLinkW_SetDescription(sl,deformated);
4933 HeapFree(GetProcessHeap(),0,deformated);
4936 if (!MSI_RecordIsNull(row,8))
4937 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
4939 if (!MSI_RecordIsNull(row,9))
4941 WCHAR *Path = NULL;
4942 INT index;
4944 sz = 0x100;
4945 MSI_RecordGetStringW(row,9,buffer,&sz);
4947 build_icon_path(package,buffer,&Path);
4948 index = MSI_RecordGetInteger(row,10);
4950 IShellLinkW_SetIconLocation(sl,Path,index);
4951 HeapFree(GetProcessHeap(),0,Path);
4954 if (!MSI_RecordIsNull(row,11))
4955 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
4957 if (!MSI_RecordIsNull(row,12))
4959 LPWSTR Path;
4960 sz = 0x100;
4961 MSI_RecordGetStringW(row,12,buffer,&sz);
4962 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
4963 IShellLinkW_SetWorkingDirectory(sl,Path);
4964 HeapFree(GetProcessHeap(), 0, Path);
4967 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
4968 IPersistFile_Save(pf,target_file,FALSE);
4970 HeapFree(GetProcessHeap(),0,target_file);
4972 IPersistFile_Release( pf );
4973 IShellLinkW_Release( sl );
4975 msiobj_release(&row->hdr);
4977 MSI_ViewClose(view);
4978 msiobj_release(&view->hdr);
4981 CoUninitialize();
4983 return rc;
4988 * 99% of the work done here is only done for
4989 * advertised installs. However this is where the
4990 * Icon table is processed and written out
4991 * so that is what I am going to do here.
4993 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4995 UINT rc;
4996 MSIQUERY * view;
4997 MSIRECORD * row = 0;
4998 static const WCHAR Query[]={
4999 'S','E','L','E','C','T',' ','*',' ',
5000 'f','r','o','m',' ','I','c','o','n',0};
5001 DWORD sz;
5002 /* for registry stuff */
5003 LPWSTR productcode;
5004 HKEY hkey=0;
5005 HKEY hukey=0;
5006 static const WCHAR szProductCode[]=
5007 {'P','r','o','d','u','c','t','C','o','d','e',0};
5008 static const WCHAR szProductName[] = {
5009 'P','r','o','d','u','c','t','N','a','m','e',0};
5010 static const WCHAR szPackageCode[] = {
5011 'P','a','c','k','a','g','e','C','o','d','e',0};
5012 LPWSTR buffer;
5013 DWORD size;
5014 MSIHANDLE hDb, hSumInfo;
5016 if (!package)
5017 return ERROR_INVALID_HANDLE;
5019 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
5020 if (rc != ERROR_SUCCESS)
5021 goto next;
5023 rc = MSI_ViewExecute(view, 0);
5024 if (rc != ERROR_SUCCESS)
5026 MSI_ViewClose(view);
5027 msiobj_release(&view->hdr);
5028 goto next;
5031 while (1)
5033 HANDLE the_file;
5034 WCHAR *FilePath=NULL;
5035 WCHAR *FileName=NULL;
5036 CHAR buffer[1024];
5038 rc = MSI_ViewFetch(view,&row);
5039 if (rc != ERROR_SUCCESS)
5041 rc = ERROR_SUCCESS;
5042 break;
5045 FileName = load_dynamic_stringW(row,1);
5046 if (!FileName)
5048 ERR("Unable to get FileName\n");
5049 msiobj_release(&row->hdr);
5050 continue;
5053 build_icon_path(package,FileName,&FilePath);
5055 HeapFree(GetProcessHeap(),0,FileName);
5057 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
5059 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
5060 FILE_ATTRIBUTE_NORMAL, NULL);
5062 if (the_file == INVALID_HANDLE_VALUE)
5064 ERR("Unable to create file %s\n",debugstr_w(FilePath));
5065 msiobj_release(&row->hdr);
5066 HeapFree(GetProcessHeap(),0,FilePath);
5067 continue;
5072 DWORD write;
5073 sz = 1024;
5074 rc = MSI_RecordReadStream(row,2,buffer,&sz);
5075 if (rc != ERROR_SUCCESS)
5077 ERR("Failed to get stream\n");
5078 CloseHandle(the_file);
5079 DeleteFileW(FilePath);
5080 break;
5082 WriteFile(the_file,buffer,sz,&write,NULL);
5083 } while (sz == 1024);
5085 HeapFree(GetProcessHeap(),0,FilePath);
5087 CloseHandle(the_file);
5088 msiobj_release(&row->hdr);
5090 MSI_ViewClose(view);
5091 msiobj_release(&view->hdr);
5093 next:
5094 /* ok there is alot more done here but i need to figure out what */
5095 productcode = load_dynamic_property(package,szProductCode,&rc);
5096 if (!productcode)
5097 return rc;
5099 rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE);
5100 if (rc != ERROR_SUCCESS)
5101 goto end;
5103 rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
5104 if (rc != ERROR_SUCCESS)
5105 goto end;
5108 buffer = load_dynamic_property(package,szProductName,NULL);
5109 size = strlenW(buffer)*sizeof(WCHAR);
5110 RegSetValueExW(hukey,szProductName,0,REG_SZ, (LPSTR)buffer,size);
5111 HeapFree(GetProcessHeap(),0,buffer);
5112 FIXME("Need to write more keys to the user registry\n");
5114 hDb= msiobj_findhandle( &package->db->hdr );
5115 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
5116 if (rc == ERROR_SUCCESS)
5118 WCHAR guidbuffer[0x200];
5119 size = 0x200;
5120 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 8, NULL, NULL, NULL,
5121 guidbuffer, &size);
5122 if (rc == ERROR_SUCCESS)
5124 WCHAR squashed[GUID_SIZE];
5125 /* for now we only care about the first guid */
5126 LPWSTR ptr = strchrW(guidbuffer,';');
5127 if (ptr) *ptr = 0;
5128 squash_guid(guidbuffer,squashed);
5129 size = strlenW(guidbuffer)*sizeof(WCHAR);
5130 RegSetValueExW(hukey,szPackageCode,0,REG_SZ, (LPSTR)guidbuffer,
5131 size);
5134 else
5136 ERR("Unable to query Revision_Number... \n");
5137 rc = ERROR_SUCCESS;
5139 MsiCloseHandle(hSumInfo);
5141 else
5143 ERR("Unable to open Summary Information\n");
5144 rc = ERROR_SUCCESS;
5147 end:
5149 HeapFree(GetProcessHeap(),0,productcode);
5150 RegCloseKey(hkey);
5151 RegCloseKey(hukey);
5153 return rc;
5156 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
5158 UINT rc;
5159 MSIQUERY * view;
5160 MSIRECORD * row = 0;
5161 static const WCHAR ExecSeqQuery[] = {'S','e','l','e','c','t',' ','*',
5162 ' ','f','r','o','m',' ','I','n','i','F','i','l','e',0};
5163 static const WCHAR szWindowsFolder[] =
5164 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
5165 static const WCHAR szbs[] = {'\\',0};
5167 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5168 if (rc != ERROR_SUCCESS)
5170 TRACE("no IniFile table\n");
5171 return ERROR_SUCCESS;
5174 rc = MSI_ViewExecute(view, 0);
5175 if (rc != ERROR_SUCCESS)
5177 MSI_ViewClose(view);
5178 msiobj_release(&view->hdr);
5179 return rc;
5182 while (1)
5184 LPWSTR component,filename,dirproperty,section,key,value,identifier;
5185 LPWSTR deformated_section, deformated_key, deformated_value;
5186 LPWSTR folder, fullname = NULL;
5187 MSIRECORD * uirow;
5188 INT component_index,action;
5190 rc = MSI_ViewFetch(view,&row);
5191 if (rc != ERROR_SUCCESS)
5193 rc = ERROR_SUCCESS;
5194 break;
5197 component = load_dynamic_stringW(row, 8);
5198 component_index = get_loaded_component(package,component);
5199 HeapFree(GetProcessHeap(),0,component);
5201 if (package->components[component_index].ActionRequest !=
5202 INSTALLSTATE_LOCAL)
5204 TRACE("Skipping ini file due to disabled component\n");
5205 msiobj_release(&row->hdr);
5206 continue;
5209 identifier = load_dynamic_stringW(row,1);
5210 filename = load_dynamic_stringW(row,2);
5211 dirproperty = load_dynamic_stringW(row,3);
5212 section = load_dynamic_stringW(row,4);
5213 key = load_dynamic_stringW(row,5);
5214 value = load_dynamic_stringW(row,6);
5215 action = MSI_RecordGetInteger(row,7);
5217 deformat_string(package,section,&deformated_section);
5218 deformat_string(package,key,&deformated_key);
5219 deformat_string(package,value,&deformated_value);
5221 if (dirproperty)
5223 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
5224 if (!folder)
5225 folder = load_dynamic_property(package,dirproperty,NULL);
5227 else
5228 folder = load_dynamic_property(package, szWindowsFolder, NULL);
5230 if (!folder)
5232 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
5233 goto cleanup;
5237 fullname = HeapAlloc(GetProcessHeap(),0,
5238 (strlenW(folder)+strlenW(filename)+2)*sizeof(WCHAR));
5240 strcpyW(fullname,folder);
5241 if (fullname[strlenW(folder)] != '\\')
5242 strcatW(fullname,szbs);
5243 strcatW(fullname,filename);
5245 if (action == 0)
5247 TRACE("Adding value %s to section %s in %s\n",
5248 debugstr_w(deformated_key), debugstr_w(deformated_section),
5249 debugstr_w(fullname));
5250 WritePrivateProfileStringW(deformated_section, deformated_key,
5251 deformated_value, fullname);
5253 else if (action == 1)
5255 WCHAR returned[10];
5256 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
5257 returned, 10, fullname);
5258 if (returned[0] == 0)
5260 TRACE("Adding value %s to section %s in %s\n",
5261 debugstr_w(deformated_key), debugstr_w(deformated_section),
5262 debugstr_w(fullname));
5264 WritePrivateProfileStringW(deformated_section, deformated_key,
5265 deformated_value, fullname);
5268 else if (action == 3)
5270 FIXME("Append to existing section not yet implemented\n");
5273 uirow = MSI_CreateRecord(4);
5274 MSI_RecordSetStringW(uirow,1,identifier);
5275 MSI_RecordSetStringW(uirow,2,deformated_section);
5276 MSI_RecordSetStringW(uirow,3,deformated_key);
5277 MSI_RecordSetStringW(uirow,4,deformated_value);
5278 ui_actiondata(package,szWriteIniValues,uirow);
5279 msiobj_release( &uirow->hdr );
5280 cleanup:
5281 HeapFree(GetProcessHeap(),0,identifier);
5282 HeapFree(GetProcessHeap(),0,fullname);
5283 HeapFree(GetProcessHeap(),0,filename);
5284 HeapFree(GetProcessHeap(),0,key);
5285 HeapFree(GetProcessHeap(),0,value);
5286 HeapFree(GetProcessHeap(),0,section);
5287 HeapFree(GetProcessHeap(),0,dirproperty);
5288 HeapFree(GetProcessHeap(),0,folder);
5289 HeapFree(GetProcessHeap(),0,deformated_key);
5290 HeapFree(GetProcessHeap(),0,deformated_value);
5291 HeapFree(GetProcessHeap(),0,deformated_section);
5292 msiobj_release(&row->hdr);
5294 MSI_ViewClose(view);
5295 msiobj_release(&view->hdr);
5296 return rc;
5299 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
5301 UINT rc;
5302 MSIQUERY * view;
5303 MSIRECORD * row = 0;
5304 static const WCHAR ExecSeqQuery[] = {'S','e','l','e','c','t',' ','*',' ',
5305 'f','r','o','m',' ','S','e','l','f','R','e','g',0};
5307 static const WCHAR ExeStr[] = {
5308 'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','s',' ',0};
5309 STARTUPINFOW si;
5310 PROCESS_INFORMATION info;
5311 BOOL brc;
5313 memset(&si,0,sizeof(STARTUPINFOW));
5315 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5316 if (rc != ERROR_SUCCESS)
5318 TRACE("no SelfReg table\n");
5319 return ERROR_SUCCESS;
5322 rc = MSI_ViewExecute(view, 0);
5323 if (rc != ERROR_SUCCESS)
5325 MSI_ViewClose(view);
5326 msiobj_release(&view->hdr);
5327 return rc;
5330 while (1)
5332 LPWSTR filename;
5333 INT index;
5334 DWORD len;
5336 rc = MSI_ViewFetch(view,&row);
5337 if (rc != ERROR_SUCCESS)
5339 rc = ERROR_SUCCESS;
5340 break;
5343 filename = load_dynamic_stringW(row,1);
5344 index = get_loaded_file(package,filename);
5346 if (index < 0)
5348 ERR("Unable to find file id %s\n",debugstr_w(filename));
5349 HeapFree(GetProcessHeap(),0,filename);
5350 msiobj_release(&row->hdr);
5351 continue;
5353 HeapFree(GetProcessHeap(),0,filename);
5355 len = strlenW(ExeStr);
5356 len += strlenW(package->files[index].TargetPath);
5357 len +=2;
5359 filename = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
5360 strcpyW(filename,ExeStr);
5361 strcatW(filename,package->files[index].TargetPath);
5363 TRACE("Registering %s\n",debugstr_w(filename));
5364 brc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL,
5365 c_collen, &si, &info);
5367 if (brc)
5368 WaitForSingleObject(info.hProcess,INFINITE);
5370 HeapFree(GetProcessHeap(),0,filename);
5371 msiobj_release(&row->hdr);
5373 MSI_ViewClose(view);
5374 msiobj_release(&view->hdr);
5375 return rc;
5378 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
5380 LPWSTR productcode;
5381 UINT rc;
5382 DWORD i;
5383 HKEY hkey=0;
5384 HKEY hukey=0;
5385 static const WCHAR szProductCode[]=
5386 {'P','r','o','d','u','c','t','C','o','d','e',0};
5388 if (!package)
5389 return ERROR_INVALID_HANDLE;
5391 productcode = load_dynamic_property(package,szProductCode,&rc);
5392 if (!productcode)
5393 return rc;
5395 rc = MSIREG_OpenFeaturesKey(productcode,&hkey,TRUE);
5396 if (rc != ERROR_SUCCESS)
5397 goto end;
5399 rc = MSIREG_OpenUserFeaturesKey(productcode,&hukey,TRUE);
5400 if (rc != ERROR_SUCCESS)
5401 goto end;
5403 /* here the guids are base 85 encoded */
5404 for (i = 0; i < package->loaded_features; i++)
5406 LPWSTR data = NULL;
5407 GUID clsid;
5408 int j;
5409 INT size;
5411 size = package->features[i].ComponentCount*21;
5412 size +=1;
5413 if (package->features[i].Feature_Parent[0])
5414 size += strlenW(package->features[i].Feature_Parent)+2;
5416 data = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5418 data[0] = 0;
5419 for (j = 0; j < package->features[i].ComponentCount; j++)
5421 WCHAR buf[21];
5422 memset(buf,0,sizeof(buf));
5423 TRACE("From %s\n",debugstr_w(package->components
5424 [package->features[i].Components[j]].ComponentId));
5425 CLSIDFromString(package->components
5426 [package->features[i].Components[j]].ComponentId,
5427 &clsid);
5428 encode_base85_guid(&clsid,buf);
5429 TRACE("to %s\n",debugstr_w(buf));
5430 strcatW(data,buf);
5432 if (package->features[i].Feature_Parent[0])
5434 static const WCHAR sep[] = {'\2',0};
5435 strcatW(data,sep);
5436 strcatW(data,package->features[i].Feature_Parent);
5439 size = (strlenW(data)+1)*sizeof(WCHAR);
5440 RegSetValueExW(hkey,package->features[i].Feature,0,REG_SZ,
5441 (LPSTR)data,size);
5442 HeapFree(GetProcessHeap(),0,data);
5444 size = strlenW(package->features[i].Feature_Parent)*sizeof(WCHAR);
5445 RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,
5446 (LPSTR)package->features[i].Feature_Parent,size);
5449 end:
5450 RegCloseKey(hkey);
5451 RegCloseKey(hukey);
5452 HeapFree(GetProcessHeap(), 0, productcode);
5453 return rc;
5456 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
5458 static const WCHAR szProductCode[]=
5459 {'P','r','o','d','u','c','t','C','o','d','e',0};
5460 HKEY hkey=0;
5461 LPWSTR buffer;
5462 LPWSTR productcode;
5463 UINT rc,i;
5464 DWORD size;
5465 static WCHAR szNONE[] = {0};
5466 static const WCHAR szWindowsInstaler[] =
5467 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
5468 static const WCHAR szPropKeys[][80] =
5470 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0},
5471 {'A','R','P','C','O','N','T','A','C','T'},
5472 {'A','R','P','C','O','M','M','E','N','T','S',0},
5473 {'P','r','o','d','u','c','t','N','a','m','e',0},
5474 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0},
5475 {'A','R','P','H','E','L','P','L','I','N','K',0},
5476 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0},
5477 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0},
5478 {'S','O','U','R','C','E','D','I','R',0},
5479 {'M','a','n','u','f','a','c','t','u','r','e','r',0},
5480 {'A','R','P','R','E','A','D','M','E',0},
5481 {'A','R','P','S','I','Z','E',0},
5482 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0},
5483 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0},
5484 {0},
5487 static const WCHAR szRegKeys[][80] =
5489 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0},
5490 {'C','o','n','t','a','c','t',0},
5491 {'C','o','m','m','e','n','t','s',0},
5492 {'D','i','s','p','l','a','y','N','a','m','e',0},
5493 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0},
5494 {'H','e','l','p','L','i','n','k',0},
5495 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0},
5496 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0},
5497 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0},
5498 {'P','u','b','l','i','s','h','e','r',0},
5499 {'R','e','a','d','m','e',0},
5500 {'S','i','z','e',0},
5501 {'U','R','L','I','n','f','o','A','b','o','u','t',0},
5502 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0},
5503 {0},
5506 static const WCHAR path[] = {
5507 'C',':','\\','W','i','n','d','o','w','s','\\',
5508 'I','n','s','t','a','l','l','e','r','\\'};
5509 static const WCHAR fmt[] = {
5510 'C',':','\\','W','i','n','d','o','w','s','\\',
5511 'I','n','s','t','a','l','l','e','r','\\',
5512 '%','x','.','m','s','i',0};
5513 static const WCHAR szLocalPackage[]=
5514 {'L','o','c','a','l','P','a','c','k','a','g','e',0};
5515 WCHAR packagefile[MAX_PATH];
5516 INT num,start;
5518 if (!package)
5519 return ERROR_INVALID_HANDLE;
5521 productcode = load_dynamic_property(package,szProductCode,&rc);
5522 if (!productcode)
5523 return rc;
5525 rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
5526 if (rc != ERROR_SUCCESS)
5527 goto end;
5529 /* dump all the info i can grab */
5530 FIXME("Flesh out more information \n");
5532 i = 0;
5533 while (szPropKeys[i][0]!=0)
5535 buffer = load_dynamic_property(package,szPropKeys[i],&rc);
5536 if (rc != ERROR_SUCCESS)
5537 buffer = szNONE;
5538 size = strlenW(buffer)*sizeof(WCHAR);
5539 RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);
5540 i++;
5543 rc = 0x1;
5544 size = sizeof(rc);
5545 RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPSTR)&rc,size);
5547 /* copy the package locally */
5548 num = GetTickCount() & 0xffff;
5549 if (!num)
5550 num = 1;
5551 start = num;
5552 sprintfW(packagefile,fmt,num);
5555 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
5556 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
5557 if (handle != INVALID_HANDLE_VALUE)
5559 CloseHandle(handle);
5560 break;
5562 if (GetLastError() != ERROR_FILE_EXISTS &&
5563 GetLastError() != ERROR_SHARING_VIOLATION)
5564 break;
5565 if (!(++num & 0xffff)) num = 1;
5566 sprintfW(packagefile,fmt,num);
5567 } while (num != start);
5569 create_full_pathW(path);
5570 CopyFileW(package->PackagePath,packagefile,FALSE);
5571 size = strlenW(packagefile)/sizeof(WCHAR);
5572 RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size);
5574 end:
5575 HeapFree(GetProcessHeap(),0,productcode);
5576 RegCloseKey(hkey);
5578 return ERROR_SUCCESS;
5581 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5583 int i;
5584 if (!package)
5585 return ERROR_INVALID_HANDLE;
5587 for (i = 0; i < package->DeferredActionCount; i++)
5589 LPWSTR action;
5590 action = package->DeferredAction[i];
5591 ui_actionstart(package, action);
5592 TRACE("Executing Action (%s)\n",debugstr_w(action));
5593 ACTION_CustomAction(package,action,TRUE);
5594 HeapFree(GetProcessHeap(),0,package->DeferredAction[i]);
5596 HeapFree(GetProcessHeap(),0,package->DeferredAction);
5598 package->DeferredActionCount = 0;
5599 package->DeferredAction = NULL;
5601 return ERROR_SUCCESS;
5604 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5606 int i;
5607 if (!package)
5608 return ERROR_INVALID_HANDLE;
5610 for (i = 0; i < package->CommitActionCount; i++)
5612 LPWSTR action;
5613 action = package->CommitAction[i];
5614 ui_actionstart(package, action);
5615 TRACE("Executing Commit Action (%s)\n",debugstr_w(action));
5616 ACTION_CustomAction(package,action,TRUE);
5617 HeapFree(GetProcessHeap(),0,package->CommitAction[i]);
5619 HeapFree(GetProcessHeap(),0,package->CommitAction);
5621 package->CommitActionCount = 0;
5622 package->CommitAction = NULL;
5624 return ERROR_SUCCESS;
5627 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
5629 static const WCHAR RunOnce[] = {
5630 'S','o','f','t','w','a','r','e','\\',
5631 'M','i','c','r','o','s','o','f','t','\\',
5632 'W','i','n','d','o','w','s','\\',
5633 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5634 'R','u','n','O','n','c','e'};
5635 static const WCHAR InstallRunOnce[] = {
5636 'S','o','f','t','w','a','r','e','\\',
5637 'M','i','c','r','o','s','o','f','t','\\',
5638 'W','i','n','d','o','w','s','\\',
5639 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5640 'I','n','s','t','a','l','l','e','r','\\',
5641 'R','u','n','O','n','c','e','E','n','t','r','i','e','s'};
5643 static const WCHAR msiexec_fmt[] = {
5644 'C',':','\\','W','i','n','d','o','w','s','\\','S','y','s','t','e','m',
5645 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5646 '\"','%','s','\"',0};
5647 static const WCHAR install_fmt[] = {
5648 '/','I',' ','\"','%','s','\"',' ',
5649 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5650 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5651 WCHAR buffer[256];
5652 HKEY hkey,hukey;
5653 LPWSTR productcode;
5654 WCHAR squished_pc[100];
5655 INT rc;
5656 DWORD size;
5657 static const WCHAR szProductCode[]=
5658 {'P','r','o','d','u','c','t','C','o','d','e',0};
5659 static const WCHAR szLUS[] = {
5660 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0};
5661 static const WCHAR szSourceList[] = {
5662 'S','o','u','r','c','e','L','i','s','t',0};
5663 static const WCHAR szPackageName[] = {
5664 'P','a','c','k','a','g','e','N','a','m','e',0};
5666 if (!package)
5667 return ERROR_INVALID_HANDLE;
5669 productcode = load_dynamic_property(package,szProductCode,&rc);
5670 if (!productcode)
5671 return rc;
5673 squash_guid(productcode,squished_pc);
5675 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5676 sprintfW(buffer,msiexec_fmt,squished_pc);
5678 size = strlenW(buffer)*sizeof(WCHAR);
5679 RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
5680 RegCloseKey(hkey);
5682 TRACE("Reboot command %s\n",debugstr_w(buffer));
5684 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5685 sprintfW(buffer,install_fmt,productcode,squished_pc);
5686 RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
5687 RegCloseKey(hkey);
5689 rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
5690 if (rc == ERROR_SUCCESS)
5692 HKEY hukey2;
5693 LPWSTR buf;
5694 RegCreateKeyW(hukey, szSourceList, &hukey2);
5695 buf = load_dynamic_property(package,cszSourceDir,NULL);
5696 size = strlenW(buf)*sizeof(WCHAR);
5697 RegSetValueExW(hukey2,szLUS,0,REG_SZ,(LPSTR)buf,size);
5698 HeapFree(GetProcessHeap(),0,buf);
5700 buf = strrchrW(package->PackagePath,'\\');
5701 if (buf)
5703 buf++;
5704 size = strlenW(buf)*sizeof(WCHAR);
5705 RegSetValueExW(hukey2,szPackageName,0,REG_SZ,(LPSTR)buf,size);
5708 RegCloseKey(hukey2);
5710 HeapFree(GetProcessHeap(),0,productcode);
5712 return ERROR_INSTALL_SUSPEND;
5715 /* Msi functions that seem appropriate here */
5716 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
5718 LPWSTR szwAction;
5719 UINT rc;
5721 TRACE(" exteral attempt at action %s\n",szAction);
5723 if (!szAction)
5724 return ERROR_FUNCTION_FAILED;
5725 if (hInstall == 0)
5726 return ERROR_FUNCTION_FAILED;
5728 szwAction = strdupAtoW(szAction);
5730 if (!szwAction)
5731 return ERROR_FUNCTION_FAILED;
5734 rc = MsiDoActionW(hInstall, szwAction);
5735 HeapFree(GetProcessHeap(),0,szwAction);
5736 return rc;
5739 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
5741 MSIPACKAGE *package;
5742 UINT ret = ERROR_INVALID_HANDLE;
5744 TRACE(" external attempt at action %s \n",debugstr_w(szAction));
5746 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5747 if( package )
5749 ret = ACTION_PerformAction(package,szAction);
5750 msiobj_release( &package->hdr );
5752 return ret;
5755 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
5756 LPSTR szPathBuf, DWORD* pcchPathBuf)
5758 LPWSTR szwFolder;
5759 LPWSTR szwPathBuf;
5760 UINT rc;
5762 TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
5764 if (!szFolder)
5765 return ERROR_FUNCTION_FAILED;
5766 if (hInstall == 0)
5767 return ERROR_FUNCTION_FAILED;
5769 szwFolder = strdupAtoW(szFolder);
5771 if (!szwFolder)
5772 return ERROR_FUNCTION_FAILED;
5774 szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
5776 rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
5778 WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
5779 *pcchPathBuf, NULL, NULL );
5781 HeapFree(GetProcessHeap(),0,szwFolder);
5782 HeapFree(GetProcessHeap(),0,szwPathBuf);
5784 return rc;
5787 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
5788 szPathBuf, DWORD* pcchPathBuf)
5790 LPWSTR path;
5791 UINT rc = ERROR_FUNCTION_FAILED;
5792 MSIPACKAGE *package;
5794 TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
5796 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5797 if (!package)
5798 return ERROR_INVALID_HANDLE;
5799 path = resolve_folder(package, szFolder, FALSE, FALSE, NULL);
5800 msiobj_release( &package->hdr );
5802 if (path && (strlenW(path) > *pcchPathBuf))
5804 *pcchPathBuf = strlenW(path)+1;
5805 rc = ERROR_MORE_DATA;
5807 else if (path)
5809 *pcchPathBuf = strlenW(path)+1;
5810 strcpyW(szPathBuf,path);
5811 TRACE("Returning Path %s\n",debugstr_w(path));
5812 rc = ERROR_SUCCESS;
5814 HeapFree(GetProcessHeap(),0,path);
5816 return rc;
5820 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder,
5821 LPSTR szPathBuf, DWORD* pcchPathBuf)
5823 LPWSTR szwFolder;
5824 LPWSTR szwPathBuf;
5825 UINT rc;
5827 TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
5829 if (!szFolder)
5830 return ERROR_FUNCTION_FAILED;
5831 if (hInstall == 0)
5832 return ERROR_FUNCTION_FAILED;
5834 szwFolder = strdupAtoW(szFolder);
5835 if (!szwFolder)
5836 return ERROR_FUNCTION_FAILED;
5838 szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
5840 rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
5842 WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
5843 *pcchPathBuf, NULL, NULL );
5845 HeapFree(GetProcessHeap(),0,szwFolder);
5846 HeapFree(GetProcessHeap(),0,szwPathBuf);
5848 return rc;
5851 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
5852 szPathBuf, DWORD* pcchPathBuf)
5854 LPWSTR path;
5855 UINT rc = ERROR_FUNCTION_FAILED;
5856 MSIPACKAGE *package;
5858 TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
5860 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5861 if( !package )
5862 return ERROR_INVALID_HANDLE;
5863 path = resolve_folder(package, szFolder, TRUE, FALSE, NULL);
5864 msiobj_release( &package->hdr );
5866 if (path && strlenW(path) > *pcchPathBuf)
5868 *pcchPathBuf = strlenW(path)+1;
5869 rc = ERROR_MORE_DATA;
5871 else if (path)
5873 *pcchPathBuf = strlenW(path)+1;
5874 strcpyW(szPathBuf,path);
5875 TRACE("Returning Path %s\n",debugstr_w(path));
5876 rc = ERROR_SUCCESS;
5878 HeapFree(GetProcessHeap(),0,path);
5880 return rc;
5884 UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder,
5885 LPCSTR szFolderPath)
5887 LPWSTR szwFolder;
5888 LPWSTR szwFolderPath;
5889 UINT rc;
5891 if (!szFolder)
5892 return ERROR_FUNCTION_FAILED;
5893 if (hInstall == 0)
5894 return ERROR_FUNCTION_FAILED;
5896 szwFolder = strdupAtoW(szFolder);
5897 if (!szwFolder)
5898 return ERROR_FUNCTION_FAILED;
5900 szwFolderPath = strdupAtoW(szFolderPath);
5901 if (!szwFolderPath)
5903 HeapFree(GetProcessHeap(),0,szwFolder);
5904 return ERROR_FUNCTION_FAILED;
5907 rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
5909 HeapFree(GetProcessHeap(),0,szwFolder);
5910 HeapFree(GetProcessHeap(),0,szwFolderPath);
5912 return rc;
5915 UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
5916 LPCWSTR szFolderPath)
5918 DWORD i;
5919 LPWSTR path = NULL;
5920 LPWSTR path2 = NULL;
5921 INT len;
5922 MSIFOLDER *folder;
5924 TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
5926 if (package==NULL)
5927 return ERROR_INVALID_HANDLE;
5929 if (szFolderPath[0]==0)
5930 return ERROR_FUNCTION_FAILED;
5932 if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)
5933 return ERROR_FUNCTION_FAILED;
5935 path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);
5937 if (!path)
5938 return ERROR_INVALID_PARAMETER;
5940 HeapFree(GetProcessHeap(),0,folder->Property);
5942 len = strlenW(szFolderPath);
5944 if (szFolderPath[len-1]!='\\')
5946 len +=2;
5947 folder->Property = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
5948 strcpyW(folder->Property,szFolderPath);
5949 strcatW(folder->Property,cszbs);
5951 else
5952 folder->Property = dupstrW(szFolderPath);
5954 if (strcmpiW(path, szFolderPath) == 0)
5957 * Resolved Target has not really changed, so just
5958 * set this folder and do not recalculate everything.
5960 HeapFree(GetProcessHeap(),0,folder->ResolvedTarget);
5961 folder->ResolvedTarget = NULL;
5962 path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL);
5963 HeapFree(GetProcessHeap(),0,path2);
5965 else
5967 for (i = 0; i < package->loaded_folders; i++)
5969 HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
5970 package->folders[i].ResolvedTarget=NULL;
5973 for (i = 0; i < package->loaded_folders; i++)
5975 path2=resolve_folder(package, package->folders[i].Directory, FALSE,
5976 TRUE, NULL);
5977 HeapFree(GetProcessHeap(),0,path2);
5980 HeapFree(GetProcessHeap(),0,path);
5982 return ERROR_SUCCESS;
5985 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
5986 LPCWSTR szFolderPath)
5988 MSIPACKAGE *package;
5989 UINT ret;
5991 TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
5993 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5994 ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
5995 msiobj_release( &package->hdr );
5996 return ret;
5999 /***********************************************************************
6000 * MsiGetMode (MSI.@)
6002 * Returns an internal installer state (if it is running in a mode iRunMode)
6004 * PARAMS
6005 * hInstall [I] Handle to the installation
6006 * hRunMode [I] Checking run mode
6007 * MSIRUNMODE_ADMIN Administrative mode
6008 * MSIRUNMODE_ADVERTISE Advertisement mode
6009 * MSIRUNMODE_MAINTENANCE Maintenance mode
6010 * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled
6011 * MSIRUNMODE_LOGENABLED Log file is writing
6012 * MSIRUNMODE_OPERATIONS Operations in progress??
6013 * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed
6014 * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation
6015 * MSIRUNMODE_CABINET Files from cabinet are installed
6016 * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is supressed
6017 * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is supressed
6018 * MSIRUNMODE_RESERVED11 Reserved
6019 * MSIRUNMODE_WINDOWS9X Running under Windows95/98
6020 * MSIRUNMODE_ZAWENABLED Demand installation is supported
6021 * MSIRUNMODE_RESERVED14 Reserved
6022 * MSIRUNMODE_RESERVED15 Reserved
6023 * MSIRUNMODE_SCHEDULED called from install script
6024 * MSIRUNMODE_ROLLBACK called from rollback script
6025 * MSIRUNMODE_COMMIT called from commit script
6027 * RETURNS
6028 * In the state: TRUE
6029 * Not in the state: FALSE
6033 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
6035 FIXME("STUB (iRunMode=%i)\n",iRunMode);
6036 return TRUE;
6040 * According to the docs, when this is called it immediately recalculates
6041 * all the component states as well
6043 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
6044 INSTALLSTATE iState)
6046 LPWSTR szwFeature = NULL;
6047 UINT rc;
6049 szwFeature = strdupAtoW(szFeature);
6051 if (!szwFeature)
6052 return ERROR_FUNCTION_FAILED;
6054 rc = MsiSetFeatureStateW(hInstall,szwFeature, iState);
6056 HeapFree(GetProcessHeap(),0,szwFeature);
6058 return rc;
6061 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
6062 INSTALLSTATE iState)
6064 MSIPACKAGE* package;
6065 INT index;
6067 TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
6069 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
6070 if (!package)
6071 return ERROR_INVALID_HANDLE;
6073 index = get_loaded_feature(package,szFeature);
6074 if (index < 0)
6075 return ERROR_UNKNOWN_FEATURE;
6077 package->features[index].ActionRequest= iState;
6079 return ERROR_SUCCESS;
6082 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
6083 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
6085 LPWSTR szwFeature = NULL;
6086 UINT rc;
6088 szwFeature = strdupAtoW(szFeature);
6090 rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
6092 HeapFree( GetProcessHeap(), 0 , szwFeature);
6094 return rc;
6097 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
6098 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
6100 INT index;
6102 index = get_loaded_feature(package,szFeature);
6103 if (index < 0)
6104 return ERROR_UNKNOWN_FEATURE;
6106 if (piInstalled)
6107 *piInstalled = package->features[index].Installed;
6109 if (piAction)
6110 *piAction = package->features[index].Action;
6112 TRACE("returning %i %i\n",*piInstalled,*piAction);
6114 return ERROR_SUCCESS;
6117 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
6118 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
6120 MSIPACKAGE* package;
6121 UINT ret;
6123 TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
6124 piAction);
6126 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
6127 if (!package)
6128 return ERROR_INVALID_HANDLE;
6129 ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
6130 msiobj_release( &package->hdr );
6131 return ret;
6134 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
6135 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
6137 LPWSTR szwComponent= NULL;
6138 UINT rc;
6140 szwComponent= strdupAtoW(szComponent);
6142 rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
6144 HeapFree( GetProcessHeap(), 0 , szwComponent);
6146 return rc;
6149 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
6150 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
6152 INT index;
6154 TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
6155 piAction);
6157 index = get_loaded_component(package,szComponent);
6158 if (index < 0)
6159 return ERROR_UNKNOWN_COMPONENT;
6161 if (piInstalled)
6162 *piInstalled = package->components[index].Installed;
6164 if (piAction)
6165 *piInstalled = package->components[index].Action;
6167 return ERROR_SUCCESS;
6170 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
6171 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
6173 MSIPACKAGE* package;
6174 UINT ret;
6176 TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
6177 piInstalled, piAction);
6179 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
6180 if (!package)
6181 return ERROR_INVALID_HANDLE;
6182 ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
6183 msiobj_release( &package->hdr );
6184 return ret;
6187 #if 0
6188 static UINT ACTION_Template(MSIPACKAGE *package)
6190 UINT rc;
6191 MSIQUERY * view;
6192 MSIRECORD * row = 0;
6193 static const WCHAR ExecSeqQuery[] = {0};
6195 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6196 if (rc != ERROR_SUCCESS)
6197 return rc;
6199 rc = MSI_ViewExecute(view, 0);
6200 if (rc != ERROR_SUCCESS)
6202 MSI_ViewClose(view);
6203 msiobj_release(&view->hdr);
6204 return rc;
6207 while (1)
6209 rc = MSI_ViewFetch(view,&row);
6210 if (rc != ERROR_SUCCESS)
6212 rc = ERROR_SUCCESS;
6213 break;
6216 msiobj_release(&row->hdr);
6218 MSI_ViewClose(view);
6219 msiobj_release(&view->hdr);
6220 return rc;
6222 #endif