- Rework how we handle Feature and Component States. I have confirmed
[wine/multimedia.git] / dlls / msi / action.c
bloba6e93a8077c4a85207767654daf64ecc9cccf639
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
54 WINE_DEFAULT_DEBUG_CHANNEL(msi);
56 typedef struct tagMSIFEATURE
58 WCHAR Feature[96];
59 WCHAR Feature_Parent[96];
60 WCHAR Title[0x100];
61 WCHAR Description[0x100];
62 INT Display;
63 INT Level;
64 WCHAR Directory[96];
65 INT Attributes;
67 INSTALLSTATE Installed;
68 INSTALLSTATE ActionRequest;
69 INSTALLSTATE Action;
71 INT ComponentCount;
72 INT Components[1024]; /* yes hardcoded limit.... I am bad */
73 INT Cost;
74 } MSIFEATURE;
76 typedef struct tagMSICOMPONENT
78 WCHAR Component[96];
79 WCHAR ComponentId[96];
80 WCHAR Directory[96];
81 INT Attributes;
82 WCHAR Condition[0x100];
83 WCHAR KeyPath[96];
85 INSTALLSTATE Installed;
86 INSTALLSTATE ActionRequest;
87 INSTALLSTATE Action;
89 BOOL Enabled;
90 INT Cost;
91 } MSICOMPONENT;
93 typedef struct tagMSIFOLDER
95 LPWSTR Directory;
96 LPWSTR TargetDefault;
97 LPWSTR SourceDefault;
99 LPWSTR ResolvedTarget;
100 LPWSTR ResolvedSource;
101 LPWSTR Property; /* initially set property */
102 INT ParentIndex;
103 INT State;
104 /* 0 = uninitialized */
105 /* 1 = existing */
106 /* 2 = created remove if empty */
107 /* 3 = created persist if empty */
108 INT Cost;
109 INT Space;
110 }MSIFOLDER;
112 typedef struct tagMSIFILE
114 LPWSTR File;
115 INT ComponentIndex;
116 LPWSTR FileName;
117 INT FileSize;
118 LPWSTR Version;
119 LPWSTR Language;
120 INT Attributes;
121 INT Sequence;
123 INT State;
124 /* 0 = uninitialize */
125 /* 1 = not present */
126 /* 2 = present but replace */
127 /* 3 = present do not replace */
128 /* 4 = Installed */
129 LPWSTR SourcePath;
130 LPWSTR TargetPath;
131 BOOL Temporary;
132 }MSIFILE;
135 * Prototypes
137 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
138 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
140 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq);
141 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action);
143 static UINT ACTION_LaunchConditions(MSIPACKAGE *package);
144 static UINT ACTION_CostInitialize(MSIPACKAGE *package);
145 static UINT ACTION_CreateFolders(MSIPACKAGE *package);
146 static UINT ACTION_CostFinalize(MSIPACKAGE *package);
147 static UINT ACTION_FileCost(MSIPACKAGE *package);
148 static UINT ACTION_InstallFiles(MSIPACKAGE *package);
149 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
150 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package);
151 static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action);
152 static UINT ACTION_InstallInitialize(MSIPACKAGE *package);
153 static UINT ACTION_InstallValidate(MSIPACKAGE *package);
154 static UINT ACTION_ProcessComponents(MSIPACKAGE *package);
155 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package);
156 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
157 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
158 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package);
159 static UINT ACTION_PublishProduct(MSIPACKAGE *package);
161 static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source,
162 const LPWSTR target, const INT type);
163 static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source,
164 const LPWSTR target, const INT type);
165 static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source,
166 const LPWSTR target, const INT type);
167 static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source,
168 const LPWSTR target, const INT type);
169 static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source,
170 const LPWSTR target, const INT type);
172 static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data);
173 static LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name,
174 BOOL source, BOOL set_prop, MSIFOLDER **folder);
176 static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path);
179 * consts and values used
181 static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
182 static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
183 static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
184 static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
185 static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
186 static const WCHAR c_collen[] = {'C',':','\\',0};
188 static const WCHAR cszlsb[]={'[',0};
189 static const WCHAR cszrsb[]={']',0};
190 static const WCHAR cszbs[]={'\\',0};
192 const static WCHAR szCreateFolders[] =
193 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
194 const static WCHAR szCostFinalize[] =
195 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
196 const static WCHAR szInstallFiles[] =
197 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
198 const static WCHAR szDuplicateFiles[] =
199 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
200 const static WCHAR szWriteRegistryValues[] =
201 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
202 const static WCHAR szCostInitialize[] =
203 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
204 const static WCHAR szFileCost[] = {'F','i','l','e','C','o','s','t',0};
205 const static WCHAR szInstallInitialize[] =
206 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
207 const static WCHAR szInstallValidate[] =
208 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
209 const static WCHAR szLaunchConditions[] =
210 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
211 const static WCHAR szProcessComponents[] =
212 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
213 const static WCHAR szRegisterTypeLibraries[] =
214 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r',
215 'i','e','s',0};
216 const static WCHAR szRegisterClassInfo[] =
217 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
218 const static WCHAR szRegisterProgIdInfo[] =
219 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
220 const static WCHAR szCreateShortcuts[] =
221 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
222 const static WCHAR szPublishProduct[] =
223 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
225 /********************************************************
226 * helper functions to get around current HACKS and such
227 ********************************************************/
228 inline static void reduce_to_longfilename(WCHAR* filename)
230 LPWSTR p = strchrW(filename,'|');
231 if (p)
232 memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR));
235 inline static char *strdupWtoA( const WCHAR *str )
237 char *ret = NULL;
238 if (str)
240 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL
242 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
243 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
245 return ret;
248 inline static WCHAR *strdupAtoW( const char *str )
250 WCHAR *ret = NULL;
251 if (str)
253 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
254 if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
255 MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
257 return ret;
260 static LPWSTR dupstrW(LPCWSTR src)
262 LPWSTR dest;
263 if (!src) return NULL;
264 dest = HeapAlloc(GetProcessHeap(), 0, (strlenW(src)+1)*sizeof(WCHAR));
265 strcpyW(dest, src);
266 return dest;
269 inline static WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
271 UINT rc;
272 DWORD sz;
273 LPWSTR ret;
275 sz = 0;
276 if (MSI_RecordIsNull(row,index))
277 return NULL;
279 rc = MSI_RecordGetStringW(row,index,NULL,&sz);
281 /* having an empty string is different than NULL */
282 if (sz == 0)
284 ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR));
285 ret[0] = 0;
286 return ret;
289 sz ++;
290 ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
291 rc = MSI_RecordGetStringW(row,index,ret,&sz);
292 if (rc!=ERROR_SUCCESS)
294 ERR("Unable to load dynamic string\n");
295 HeapFree(GetProcessHeap(), 0, ret);
296 ret = NULL;
298 return ret;
301 inline static LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop,
302 UINT* rc)
304 DWORD sz = 0;
305 LPWSTR str;
306 UINT r;
308 r = MSI_GetPropertyW(package, prop, NULL, &sz);
309 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
311 if (rc)
312 *rc = r;
313 return NULL;
315 sz++;
316 str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
317 r = MSI_GetPropertyW(package, prop, str, &sz);
318 if (r != ERROR_SUCCESS)
320 HeapFree(GetProcessHeap(),0,str);
321 str = NULL;
323 if (rc)
324 *rc = r;
325 return str;
328 inline static int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
330 int rc = -1;
331 DWORD i;
333 for (i = 0; i < package->loaded_components; i++)
335 if (strcmpW(Component,package->components[i].Component)==0)
337 rc = i;
338 break;
341 return rc;
344 inline static int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
346 int rc = -1;
347 DWORD i;
349 for (i = 0; i < package->loaded_features; i++)
351 if (strcmpW(Feature,package->features[i].Feature)==0)
353 rc = i;
354 break;
357 return rc;
360 inline static int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
362 int rc = -1;
363 DWORD i;
365 for (i = 0; i < package->loaded_files; i++)
367 if (strcmpW(file,package->files[i].File)==0)
369 rc = i;
370 break;
373 return rc;
377 static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
379 DWORD i;
380 DWORD index;
382 if (!package)
383 return -2;
385 for (i=0; i < package->loaded_files; i++)
386 if (strcmpW(package->files[i].File,name)==0)
387 return -1;
389 index = package->loaded_files;
390 package->loaded_files++;
391 if (package->loaded_files== 1)
392 package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
393 else
394 package->files = HeapReAlloc(GetProcessHeap(),0,
395 package->files , package->loaded_files * sizeof(MSIFILE));
397 memset(&package->files[index],0,sizeof(MSIFILE));
399 package->files[index].File = dupstrW(name);
400 package->files[index].TargetPath = dupstrW(path);
401 package->files[index].Temporary = TRUE;
403 TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));
405 return 0;
408 void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package)
410 DWORD i;
412 if (!package)
413 return;
415 for (i = 0; i < package->loaded_files; i++)
417 if (package->files[i].Temporary)
419 TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));
420 DeleteFileW(package->files[i].TargetPath);
426 static UINT ACTION_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
428 LPWSTR szQuery;
429 LPCWSTR p;
430 UINT sz, rc;
431 va_list va;
433 /* figure out how much space we need to allocate */
434 va_start(va, fmt);
435 sz = strlenW(fmt) + 1;
436 p = fmt;
437 while (*p)
439 p = strchrW(p, '%');
440 if (!p)
441 break;
442 p++;
443 switch (*p)
445 case 's': /* a string */
446 sz += strlenW(va_arg(va,LPCWSTR));
447 break;
448 case 'd':
449 case 'i': /* an integer -2147483648 seems to be longest */
450 sz += 3*sizeof(int);
451 (void)va_arg(va,int);
452 break;
453 case '%': /* a single % - leave it alone */
454 break;
455 default:
456 FIXME("Unhandled character type %c\n",*p);
458 p++;
460 va_end(va);
462 /* construct the string */
463 szQuery = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
464 va_start(va, fmt);
465 vsnprintfW(szQuery, sz, fmt, va);
466 va_end(va);
468 /* perform the query */
469 rc = MSI_DatabaseOpenViewW(db, szQuery, view);
470 HeapFree(GetProcessHeap(), 0, szQuery);
471 return rc;
474 static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )
476 MSIRECORD * row;
478 row = MSI_CreateRecord(4);
479 MSI_RecordSetInteger(row,1,a);
480 MSI_RecordSetInteger(row,2,b);
481 MSI_RecordSetInteger(row,3,c);
482 MSI_RecordSetInteger(row,4,d);
483 MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);
484 msiobj_release(&row->hdr);
487 static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
489 static const WCHAR Query_t[] =
490 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
491 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
492 ' ','\'','%','s','\'',0};
493 WCHAR message[1024];
494 UINT rc;
495 MSIQUERY * view;
496 MSIRECORD * row = 0;
497 LPWSTR ptr;
499 if (!package->LastAction || strcmpW(package->LastAction,action))
501 rc = ACTION_OpenQuery(package->db, &view, Query_t, action);
502 if (rc != ERROR_SUCCESS)
503 return;
505 rc = MSI_ViewExecute(view, 0);
506 if (rc != ERROR_SUCCESS)
508 MSI_ViewClose(view);
509 return;
511 rc = MSI_ViewFetch(view,&row);
512 if (rc != ERROR_SUCCESS)
514 MSI_ViewClose(view);
515 return;
518 if (MSI_RecordIsNull(row,3))
520 msiobj_release(&row->hdr);
521 MSI_ViewClose(view);
522 msiobj_release(&view->hdr);
523 return;
526 /* update the cached actionformat */
527 if (package->ActionFormat)
528 HeapFree(GetProcessHeap(),0,package->ActionFormat);
529 package->ActionFormat = load_dynamic_stringW(row,3);
531 if (package->LastAction)
532 HeapFree(GetProcessHeap(),0,package->LastAction);
533 package->LastAction = dupstrW(action);
535 msiobj_release(&row->hdr);
536 MSI_ViewClose(view);
537 msiobj_release(&view->hdr);
540 message[0]=0;
541 ptr = package->ActionFormat;
542 while (*ptr)
544 LPWSTR ptr2;
545 LPWSTR data=NULL;
546 WCHAR tmp[1023];
547 INT field;
549 ptr2 = strchrW(ptr,'[');
550 if (ptr2)
552 strncpyW(tmp,ptr,ptr2-ptr);
553 tmp[ptr2-ptr]=0;
554 strcatW(message,tmp);
555 ptr2++;
556 field = atoiW(ptr2);
557 data = load_dynamic_stringW(record,field);
558 if (data)
560 strcatW(message,data);
561 HeapFree(GetProcessHeap(),0,data);
563 ptr=strchrW(ptr2,']');
564 ptr++;
566 else
568 strcatW(message,ptr);
569 break;
573 row = MSI_CreateRecord(1);
574 MSI_RecordSetStringW(row,1,message);
576 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
577 msiobj_release(&row->hdr);
581 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
583 static const WCHAR template_s[]=
584 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ','%','s','.',0};
585 static const WCHAR format[] =
586 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
587 static const WCHAR Query_t[] =
588 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
589 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
590 ' ','\'','%','s','\'',0};
591 WCHAR message[1024];
592 WCHAR timet[0x100];
593 UINT rc;
594 MSIQUERY * view;
595 MSIRECORD * row = 0;
596 WCHAR *ActionText=NULL;
598 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
600 rc = ACTION_OpenQuery(package->db, &view, Query_t, action);
601 if (rc != ERROR_SUCCESS)
602 return;
603 rc = MSI_ViewExecute(view, 0);
604 if (rc != ERROR_SUCCESS)
606 MSI_ViewClose(view);
607 msiobj_release(&view->hdr);
608 return;
610 rc = MSI_ViewFetch(view,&row);
611 if (rc != ERROR_SUCCESS)
613 MSI_ViewClose(view);
614 msiobj_release(&view->hdr);
615 return;
618 ActionText = load_dynamic_stringW(row,2);
619 msiobj_release(&row->hdr);
620 MSI_ViewClose(view);
621 msiobj_release(&view->hdr);
623 sprintfW(message,template_s,timet,action,ActionText);
625 row = MSI_CreateRecord(1);
626 MSI_RecordSetStringW(row,1,message);
628 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
629 msiobj_release(&row->hdr);
630 HeapFree(GetProcessHeap(),0,ActionText);
633 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
634 UINT rc)
636 MSIRECORD * row;
637 static const WCHAR template_s[]=
638 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ','%','s',
639 '.',0};
640 static const WCHAR template_e[]=
641 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ','%','s',
642 '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ','%','i','.',0};
643 static const WCHAR format[] =
644 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
645 WCHAR message[1024];
646 WCHAR timet[0x100];
648 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
649 if (start)
650 sprintfW(message,template_s,timet,action);
651 else
652 sprintfW(message,template_e,timet,action,rc);
654 row = MSI_CreateRecord(1);
655 MSI_RecordSetStringW(row,1,message);
657 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
658 msiobj_release(&row->hdr);
662 * build_directory_name()
664 * This function is to save messing round with directory names
665 * It handles adding backslashes between path segments,
666 * and can add \ at the end of the directory name if told to.
668 * It takes a variable number of arguments.
669 * It always allocates a new string for the result, so make sure
670 * to free the return value when finished with it.
672 * The first arg is the number of path segments that follow.
673 * The arguments following count are a list of path segments.
674 * A path segment may be NULL.
676 * Path segments will be added with a \ seperating them.
677 * A \ will not be added after the last segment, however if the
678 * last segment is NULL, then the last character will be a \
681 static LPWSTR build_directory_name(DWORD count, ...)
683 DWORD sz = 1, i;
684 LPWSTR dir;
685 va_list va;
687 va_start(va,count);
688 for(i=0; i<count; i++)
690 LPCWSTR str = va_arg(va,LPCWSTR);
691 if (str)
692 sz += strlenW(str) + 1;
694 va_end(va);
696 dir = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
697 dir[0]=0;
699 va_start(va,count);
700 for(i=0; i<count; i++)
702 LPCWSTR str = va_arg(va,LPCWSTR);
703 if (!str)
704 continue;
705 strcatW(dir, str);
706 if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\\')
707 strcatW(dir, cszbs);
709 return dir;
713 /****************************************************
714 * TOP level entry points
715 *****************************************************/
717 UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
718 LPCWSTR szCommandLine)
720 DWORD sz;
721 WCHAR buffer[10];
722 UINT rc;
723 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
725 if (szPackagePath)
727 LPWSTR p, check, path;
729 path = dupstrW(szPackagePath);
730 p = strrchrW(path,'\\');
731 if (p)
733 p++;
734 *p=0;
737 check = load_dynamic_property(package, cszSourceDir,NULL);
738 if (!check)
739 MSI_SetPropertyW(package, cszSourceDir, path);
740 else
741 HeapFree(GetProcessHeap(), 0, check);
743 HeapFree(GetProcessHeap(), 0, path);
746 if (szCommandLine)
748 LPWSTR ptr,ptr2;
749 ptr = (LPWSTR)szCommandLine;
751 while (*ptr)
753 WCHAR *prop = NULL;
754 WCHAR *val = NULL;
756 TRACE("Looking at %s\n",debugstr_w(ptr));
758 ptr2 = strchrW(ptr,'=');
759 if (ptr2)
761 BOOL quote=FALSE;
762 DWORD len = 0;
764 while (*ptr == ' ') ptr++;
765 len = ptr2-ptr;
766 prop = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
767 strncpyW(prop,ptr,len);
768 prop[len]=0;
769 ptr2++;
771 len = 0;
772 ptr = ptr2;
773 while (*ptr && (quote || (!quote && *ptr!=' ')))
775 if (*ptr == '"')
776 quote = !quote;
777 ptr++;
778 len++;
781 if (*ptr2=='"')
783 ptr2++;
784 len -= 2;
786 val = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
787 strncpyW(val,ptr2,len);
788 val[len] = 0;
790 if (strlenW(prop) > 0)
792 TRACE("Found commandline property (%s) = (%s)\n",
793 debugstr_w(prop), debugstr_w(val));
794 MSI_SetPropertyW(package,prop,val);
796 HeapFree(GetProcessHeap(),0,val);
797 HeapFree(GetProcessHeap(),0,prop);
799 ptr++;
803 sz = 10;
804 if (MSI_GetPropertyW(package,szUILevel,buffer,&sz) == ERROR_SUCCESS)
806 if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED)
808 rc = ACTION_ProcessUISequence(package);
809 if (rc == ERROR_SUCCESS)
810 rc = ACTION_ProcessExecSequence(package,TRUE);
812 else
813 rc = ACTION_ProcessExecSequence(package,FALSE);
815 else
816 rc = ACTION_ProcessExecSequence(package,FALSE);
818 /* process the ending type action */
819 if (rc == ERROR_SUCCESS)
820 rc = ACTION_PerformActionSequence(package,-1);
821 else if (rc == ERROR_FUNCTION_FAILED)
822 rc = ACTION_PerformActionSequence(package,-3);
824 return rc;
827 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
829 MSIQUERY * view;
830 UINT rc;
831 WCHAR buffer[0x100];
832 DWORD sz = 0x100;
833 MSIRECORD * row = 0;
834 static const WCHAR ExecSeqQuery[] = {
835 's','e','l','e','c','t',' ','*',' ',
836 'f','r','o','m',' ',
837 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
838 'S','e','q','u','e','n','c','e',' ',
839 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
840 '=',' ','%','i',0};
842 rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, seq);
844 if (rc == ERROR_SUCCESS)
846 rc = MSI_ViewExecute(view, 0);
848 if (rc != ERROR_SUCCESS)
850 MSI_ViewClose(view);
851 msiobj_release(&view->hdr);
852 goto end;
855 TRACE("Running the actions\n");
857 rc = MSI_ViewFetch(view,&row);
858 if (rc != ERROR_SUCCESS)
860 rc = ERROR_SUCCESS;
861 goto end;
864 /* check conditions */
865 if (!MSI_RecordIsNull(row,2))
867 LPWSTR cond = NULL;
868 cond = load_dynamic_stringW(row,2);
870 if (cond)
872 /* this is a hack to skip errors in the condition code */
873 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
875 HeapFree(GetProcessHeap(),0,cond);
876 msiobj_release(&row->hdr);
877 goto end;
879 else
880 HeapFree(GetProcessHeap(),0,cond);
884 sz=0x100;
885 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
886 if (rc != ERROR_SUCCESS)
888 ERR("Error is %x\n",rc);
889 msiobj_release(&row->hdr);
890 goto end;
893 rc = ACTION_PerformAction(package,buffer);
894 msiobj_release(&row->hdr);
895 end:
896 MSI_ViewClose(view);
897 msiobj_release(&view->hdr);
899 else
900 rc = ERROR_SUCCESS;
902 return rc;
905 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
907 MSIQUERY * view;
908 UINT rc;
909 static const WCHAR ExecSeqQuery[] = {
910 's','e','l','e','c','t',' ','*',' ',
911 'f','r','o','m',' ',
912 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
913 'S','e','q','u','e','n','c','e',' ',
914 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
915 '>',' ','%','i',' ','o','r','d','e','r',' ',
916 'b','y',' ','S','e','q','u','e','n','c','e',0 };
917 MSIRECORD * row = 0;
918 static const WCHAR IVQuery[] = {
919 's','e','l','e','c','t',' ','S','e','q','u','e','n','c','e',' ',
920 'f','r','o','m',' ','I','n','s','t','a','l','l',
921 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e',' ',
922 'w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',' ',
923 '`','I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`',
925 INT seq = 0;
927 /* get the sequence number */
928 if (UIran)
930 rc = MSI_DatabaseOpenViewW(package->db, IVQuery, &view);
931 if (rc != ERROR_SUCCESS)
932 return rc;
933 rc = MSI_ViewExecute(view, 0);
934 if (rc != ERROR_SUCCESS)
936 MSI_ViewClose(view);
937 msiobj_release(&view->hdr);
938 return rc;
940 rc = MSI_ViewFetch(view,&row);
941 if (rc != ERROR_SUCCESS)
943 MSI_ViewClose(view);
944 msiobj_release(&view->hdr);
945 return rc;
947 seq = MSI_RecordGetInteger(row,1);
948 msiobj_release(&row->hdr);
949 MSI_ViewClose(view);
950 msiobj_release(&view->hdr);
953 rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, seq);
954 if (rc == ERROR_SUCCESS)
956 rc = MSI_ViewExecute(view, 0);
958 if (rc != ERROR_SUCCESS)
960 MSI_ViewClose(view);
961 msiobj_release(&view->hdr);
962 goto end;
965 TRACE("Running the actions\n");
967 while (1)
969 WCHAR buffer[0x100];
970 DWORD sz = 0x100;
972 rc = MSI_ViewFetch(view,&row);
973 if (rc != ERROR_SUCCESS)
975 rc = ERROR_SUCCESS;
976 break;
979 /* check conditions */
980 if (!MSI_RecordIsNull(row,2))
982 LPWSTR cond = NULL;
983 cond = load_dynamic_stringW(row,2);
985 if (cond)
987 /* this is a hack to skip errors in the condition code */
988 if (MSI_EvaluateConditionW(package, cond) ==
989 MSICONDITION_FALSE)
991 HeapFree(GetProcessHeap(),0,cond);
992 msiobj_release(&row->hdr);
993 continue;
995 else
996 HeapFree(GetProcessHeap(),0,cond);
1000 sz=0x100;
1001 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
1002 if (rc != ERROR_SUCCESS)
1004 ERR("Error is %x\n",rc);
1005 msiobj_release(&row->hdr);
1006 break;
1009 rc = ACTION_PerformAction(package,buffer);
1011 if (rc == ERROR_FUNCTION_NOT_CALLED)
1012 rc = ERROR_SUCCESS;
1014 if (rc != ERROR_SUCCESS)
1016 ERR("Execution halted due to error (%i)\n",rc);
1017 msiobj_release(&row->hdr);
1018 break;
1021 msiobj_release(&row->hdr);
1024 MSI_ViewClose(view);
1025 msiobj_release(&view->hdr);
1028 end:
1029 return rc;
1033 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1035 MSIQUERY * view;
1036 UINT rc;
1037 static const WCHAR ExecSeqQuery [] = {
1038 's','e','l','e','c','t',' ','*',' ',
1039 'f','r','o','m',' ','I','n','s','t','a','l','l',
1040 'U','I','S','e','q','u','e','n','c','e',' ',
1041 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', '>',' ','0',' ',
1042 'o','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e',0};
1044 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1046 if (rc == ERROR_SUCCESS)
1048 rc = MSI_ViewExecute(view, 0);
1050 if (rc != ERROR_SUCCESS)
1052 MSI_ViewClose(view);
1053 msiobj_release(&view->hdr);
1054 goto end;
1057 TRACE("Running the actions \n");
1059 while (1)
1061 WCHAR buffer[0x100];
1062 DWORD sz = 0x100;
1063 MSIRECORD * row = 0;
1065 rc = MSI_ViewFetch(view,&row);
1066 if (rc != ERROR_SUCCESS)
1068 rc = ERROR_SUCCESS;
1069 break;
1072 /* check conditions */
1073 if (!MSI_RecordIsNull(row,2))
1075 LPWSTR cond = NULL;
1076 cond = load_dynamic_stringW(row,2);
1078 if (cond)
1080 /* this is a hack to skip errors in the condition code */
1081 if (MSI_EvaluateConditionW(package, cond) ==
1082 MSICONDITION_FALSE)
1084 HeapFree(GetProcessHeap(),0,cond);
1085 msiobj_release(&row->hdr);
1086 continue;
1088 else
1089 HeapFree(GetProcessHeap(),0,cond);
1093 sz=0x100;
1094 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
1095 if (rc != ERROR_SUCCESS)
1097 ERR("Error is %x\n",rc);
1098 msiobj_release(&row->hdr);
1099 break;
1102 rc = ACTION_PerformAction(package,buffer);
1104 if (rc == ERROR_FUNCTION_NOT_CALLED)
1105 rc = ERROR_SUCCESS;
1107 if (rc != ERROR_SUCCESS)
1109 ERR("Execution halted due to error (%i)\n",rc);
1110 msiobj_release(&row->hdr);
1111 break;
1114 msiobj_release(&row->hdr);
1117 MSI_ViewClose(view);
1118 msiobj_release(&view->hdr);
1121 end:
1122 return rc;
1125 /********************************************************
1126 * ACTION helper functions and functions that perform the actions
1127 *******************************************************/
1130 * Alot of actions are really important even if they don't do anything
1131 * explicit.. Lots of properties are set at the beginning of the installation
1132 * CostFinalize does a bunch of work to translated the directories and such
1134 * But until I get write access to the database that is hard, so I am going to
1135 * hack it to see if I can get something to run.
1137 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action)
1139 UINT rc = ERROR_SUCCESS;
1141 TRACE("Performing action (%s)\n",debugstr_w(action));
1142 ui_actioninfo(package, action, TRUE, 0);
1143 ui_actionstart(package, action);
1144 ui_progress(package,2,1,0,0);
1146 /* pre install, setup and configuration block */
1147 if (strcmpW(action,szLaunchConditions)==0)
1148 rc = ACTION_LaunchConditions(package);
1149 else if (strcmpW(action,szCostInitialize)==0)
1150 rc = ACTION_CostInitialize(package);
1151 else if (strcmpW(action,szFileCost)==0)
1152 rc = ACTION_FileCost(package);
1153 else if (strcmpW(action,szCostFinalize)==0)
1154 rc = ACTION_CostFinalize(package);
1155 else if (strcmpW(action,szInstallValidate)==0)
1156 rc = ACTION_InstallValidate(package);
1158 /* install block */
1159 else if (strcmpW(action,szProcessComponents)==0)
1160 rc = ACTION_ProcessComponents(package);
1161 else if (strcmpW(action,szInstallInitialize)==0)
1162 rc = ACTION_InstallInitialize(package);
1163 else if (strcmpW(action,szCreateFolders)==0)
1164 rc = ACTION_CreateFolders(package);
1165 else if (strcmpW(action,szInstallFiles)==0)
1166 rc = ACTION_InstallFiles(package);
1167 else if (strcmpW(action,szDuplicateFiles)==0)
1168 rc = ACTION_DuplicateFiles(package);
1169 else if (strcmpW(action,szWriteRegistryValues)==0)
1170 rc = ACTION_WriteRegistryValues(package);
1171 else if (strcmpW(action,szRegisterTypeLibraries)==0)
1172 rc = ACTION_RegisterTypeLibraries(package);
1173 else if (strcmpW(action,szRegisterClassInfo)==0)
1174 rc = ACTION_RegisterClassInfo(package);
1175 else if (strcmpW(action,szRegisterProgIdInfo)==0)
1176 rc = ACTION_RegisterProgIdInfo(package);
1177 else if (strcmpW(action,szCreateShortcuts)==0)
1178 rc = ACTION_CreateShortcuts(package);
1179 else if (strcmpW(action,szPublishProduct)==0)
1180 rc = ACTION_PublishProduct(package);
1183 Called during iTunes but unimplemented and seem important
1185 ResolveSource (sets SourceDir)
1186 RegisterProduct
1187 InstallFinalize
1189 else if ((rc = ACTION_CustomAction(package,action)) != ERROR_SUCCESS)
1191 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
1192 rc = ERROR_FUNCTION_NOT_CALLED;
1195 ui_actioninfo(package, action, FALSE, rc);
1196 return rc;
1200 static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action)
1202 UINT rc = ERROR_SUCCESS;
1203 MSIQUERY * view;
1204 MSIRECORD * row = 0;
1205 static const WCHAR ExecSeqQuery[] =
1206 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','C','u','s','t','o'
1207 ,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i'
1208 ,'o','n','`',' ','=',' ','`','%','s','`',0};
1209 UINT type;
1210 LPWSTR source;
1211 LPWSTR target;
1212 WCHAR *deformated=NULL;
1214 rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, action);
1215 if (rc != ERROR_SUCCESS)
1216 return rc;
1218 rc = MSI_ViewExecute(view, 0);
1219 if (rc != ERROR_SUCCESS)
1221 MSI_ViewClose(view);
1222 msiobj_release(&view->hdr);
1223 return rc;
1226 rc = MSI_ViewFetch(view,&row);
1227 if (rc != ERROR_SUCCESS)
1229 MSI_ViewClose(view);
1230 msiobj_release(&view->hdr);
1231 return rc;
1234 type = MSI_RecordGetInteger(row,2);
1236 source = load_dynamic_stringW(row,3);
1237 target = load_dynamic_stringW(row,4);
1239 TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type,
1240 debugstr_w(source), debugstr_w(target));
1242 /* we are ignoring ALOT of flags and important synchronization stuff */
1243 switch (type & CUSTOM_ACTION_TYPE_MASK)
1245 case 1: /* DLL file stored in a Binary table stream */
1246 rc = HANDLE_CustomType1(package,source,target,type);
1247 break;
1248 case 2: /* EXE file stored in a Binary table strem */
1249 rc = HANDLE_CustomType2(package,source,target,type);
1250 break;
1251 case 18: /*EXE file installed with package */
1252 rc = HANDLE_CustomType18(package,source,target,type);
1253 break;
1254 case 50: /*EXE file specified by a property value */
1255 rc = HANDLE_CustomType50(package,source,target,type);
1256 break;
1257 case 34: /*EXE to be run in specified directory */
1258 rc = HANDLE_CustomType34(package,source,target,type);
1259 break;
1260 case 35: /* Directory set with formatted text. */
1261 case 51: /* Property set with formatted text. */
1262 deformat_string(package,target,&deformated);
1263 rc = MSI_SetPropertyW(package,source,deformated);
1264 HeapFree(GetProcessHeap(),0,deformated);
1265 break;
1266 default:
1267 FIXME("UNHANDLED ACTION TYPE %i (%s %s)\n",
1268 type & CUSTOM_ACTION_TYPE_MASK, debugstr_w(source),
1269 debugstr_w(target));
1272 HeapFree(GetProcessHeap(),0,source);
1273 HeapFree(GetProcessHeap(),0,target);
1274 msiobj_release(&row->hdr);
1275 MSI_ViewClose(view);
1276 msiobj_release(&view->hdr);
1277 return rc;
1280 static UINT store_binary_to_temp(MSIPACKAGE *package, const LPWSTR source,
1281 LPWSTR tmp_file)
1283 DWORD sz=MAX_PATH;
1285 if (MSI_GetPropertyW(package, cszTempFolder, tmp_file, &sz)
1286 != ERROR_SUCCESS)
1287 GetTempPathW(MAX_PATH,tmp_file);
1289 strcatW(tmp_file,source);
1291 if (GetFileAttributesW(tmp_file) != INVALID_FILE_ATTRIBUTES)
1293 TRACE("File already exists\n");
1294 return ERROR_SUCCESS;
1296 else
1298 /* write out the file */
1299 UINT rc;
1300 MSIQUERY * view;
1301 MSIRECORD * row = 0;
1302 static const WCHAR fmt[] =
1303 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','B','i'
1304 ,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`','%','s','`',0};
1305 HANDLE the_file;
1306 CHAR buffer[1024];
1308 if (track_tempfile(package, source, tmp_file)!=0)
1309 FIXME("File Name in temp tracking collision\n");
1311 the_file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
1312 FILE_ATTRIBUTE_NORMAL, NULL);
1314 if (the_file == INVALID_HANDLE_VALUE)
1315 return ERROR_FUNCTION_FAILED;
1317 rc = ACTION_OpenQuery(package->db, &view, fmt, source);
1318 if (rc != ERROR_SUCCESS)
1319 return rc;
1321 rc = MSI_ViewExecute(view, 0);
1322 if (rc != ERROR_SUCCESS)
1324 MSI_ViewClose(view);
1325 msiobj_release(&view->hdr);
1326 return rc;
1329 rc = MSI_ViewFetch(view,&row);
1330 if (rc != ERROR_SUCCESS)
1332 MSI_ViewClose(view);
1333 msiobj_release(&view->hdr);
1334 return rc;
1339 DWORD write;
1340 sz = 1024;
1341 rc = MSI_RecordReadStream(row,2,buffer,&sz);
1342 if (rc != ERROR_SUCCESS)
1344 ERR("Failed to get stream\n");
1345 CloseHandle(the_file);
1346 DeleteFileW(tmp_file);
1347 break;
1349 WriteFile(the_file,buffer,sz,&write,NULL);
1350 } while (sz == 1024);
1352 CloseHandle(the_file);
1354 msiobj_release(&row->hdr);
1355 MSI_ViewClose(view);
1356 msiobj_release(&view->hdr);
1359 return ERROR_SUCCESS;
1362 typedef UINT __stdcall CustomEntry(MSIHANDLE);
1363 typedef struct
1365 MSIPACKAGE *package;
1366 WCHAR *target;
1367 WCHAR *source;
1368 } thread_struct;
1370 static DWORD WINAPI DllThread(LPVOID info)
1372 HANDLE DLL;
1373 LPSTR proc;
1374 thread_struct *stuff;
1375 CustomEntry *fn;
1377 stuff = (thread_struct*)info;
1379 TRACE("Asynchronous start (%s, %s) \n", debugstr_w(stuff->source),
1380 debugstr_w(stuff->target));
1382 DLL = LoadLibraryW(stuff->source);
1383 if (DLL)
1385 proc = strdupWtoA( stuff->target );
1386 fn = (CustomEntry*)GetProcAddress(DLL,proc);
1387 if (fn)
1389 MSIHANDLE hPackage;
1390 MSIPACKAGE *package = stuff->package;
1392 TRACE("Calling function\n");
1393 hPackage = msiobj_findhandle( &package->hdr );
1394 if( !hPackage )
1395 ERR("Handle for object %p not found\n", package );
1396 fn(hPackage);
1397 msiobj_release( &package->hdr );
1399 else
1400 ERR("Cannot load functon\n");
1402 HeapFree(GetProcessHeap(),0,proc);
1403 FreeLibrary(DLL);
1405 else
1406 ERR("Unable to load library\n");
1407 msiobj_release( &stuff->package->hdr );
1408 HeapFree(GetProcessHeap(),0,stuff->source);
1409 HeapFree(GetProcessHeap(),0,stuff->target);
1410 HeapFree(GetProcessHeap(), 0, stuff);
1411 return 0;
1414 static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source,
1415 const LPWSTR target, const INT type)
1417 WCHAR tmp_file[MAX_PATH];
1418 CustomEntry *fn;
1419 HANDLE DLL;
1420 LPSTR proc;
1422 store_binary_to_temp(package, source, tmp_file);
1424 TRACE("Calling function %s from %s\n",debugstr_w(target),
1425 debugstr_w(tmp_file));
1427 if (!strchrW(tmp_file,'.'))
1429 static const WCHAR dot[]={'.',0};
1430 strcatW(tmp_file,dot);
1433 if (type & 0xc0)
1435 DWORD ThreadId;
1436 HANDLE ThreadHandle;
1437 thread_struct *info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) );
1439 msiobj_addref( &package->hdr );
1440 info->package = package;
1441 info->target = dupstrW(target);
1442 info->source = dupstrW(tmp_file);
1443 TRACE("Start Asynchronous execution of dll\n");
1444 ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId);
1445 CloseHandle(ThreadHandle);
1446 /* FIXME: release the package if the CreateThread fails */
1447 return ERROR_SUCCESS;
1450 DLL = LoadLibraryW(tmp_file);
1451 if (DLL)
1453 proc = strdupWtoA( target );
1454 fn = (CustomEntry*)GetProcAddress(DLL,proc);
1455 if (fn)
1457 MSIHANDLE hPackage;
1459 TRACE("Calling function\n");
1460 hPackage = msiobj_findhandle( &package->hdr );
1461 if( !hPackage )
1462 ERR("Handle for object %p not found\n", package );
1463 fn(hPackage);
1464 msiobj_release( &package->hdr );
1466 else
1467 ERR("Cannot load functon\n");
1469 HeapFree(GetProcessHeap(),0,proc);
1470 FreeLibrary(DLL);
1472 else
1473 ERR("Unable to load library\n");
1475 return ERROR_SUCCESS;
1478 static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source,
1479 const LPWSTR target, const INT type)
1481 WCHAR tmp_file[MAX_PATH];
1482 STARTUPINFOW si;
1483 PROCESS_INFORMATION info;
1484 BOOL rc;
1485 INT len;
1486 WCHAR *deformated;
1487 WCHAR *cmd;
1488 static const WCHAR spc[] = {' ',0};
1490 memset(&si,0,sizeof(STARTUPINFOW));
1492 store_binary_to_temp(package, source, tmp_file);
1494 deformat_string(package,target,&deformated);
1496 len = strlenW(tmp_file) + strlenW(deformated) + 2;
1498 cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len);
1500 strcpyW(cmd,tmp_file);
1501 strcatW(cmd,spc);
1502 strcatW(cmd,deformated);
1504 HeapFree(GetProcessHeap(),0,deformated);
1506 TRACE("executing exe %s \n",debugstr_w(cmd));
1508 rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
1509 c_collen, &si, &info);
1511 HeapFree(GetProcessHeap(),0,cmd);
1513 if ( !rc )
1515 ERR("Unable to execute command\n");
1516 return ERROR_SUCCESS;
1519 if (!(type & 0xc0))
1520 WaitForSingleObject(info.hProcess,INFINITE);
1522 CloseHandle( info.hProcess );
1523 CloseHandle( info.hThread );
1524 return ERROR_SUCCESS;
1527 static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source,
1528 const LPWSTR target, const INT type)
1530 STARTUPINFOW si;
1531 PROCESS_INFORMATION info;
1532 BOOL rc;
1533 WCHAR *deformated;
1534 WCHAR *cmd;
1535 INT len;
1536 static const WCHAR spc[] = {' ',0};
1537 int index;
1539 memset(&si,0,sizeof(STARTUPINFOW));
1541 index = get_loaded_file(package,source);
1543 len = strlenW(package->files[index].TargetPath);
1545 deformat_string(package,target,&deformated);
1546 len += strlenW(deformated);
1547 len += 2;
1549 cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,len * sizeof(WCHAR));
1551 strcpyW(cmd, package->files[index].TargetPath);
1552 strcatW(cmd, spc);
1553 strcatW(cmd, deformated);
1555 HeapFree(GetProcessHeap(),0,deformated);
1557 TRACE("executing exe %s \n",debugstr_w(cmd));
1559 rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
1560 c_collen, &si, &info);
1562 HeapFree(GetProcessHeap(),0,cmd);
1564 if ( !rc )
1566 ERR("Unable to execute command\n");
1567 return ERROR_SUCCESS;
1570 if (!(type & 0xc0))
1571 WaitForSingleObject(info.hProcess,INFINITE);
1573 CloseHandle( info.hProcess );
1574 CloseHandle( info.hThread );
1575 return ERROR_SUCCESS;
1578 static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source,
1579 const LPWSTR target, const INT type)
1581 STARTUPINFOW si;
1582 PROCESS_INFORMATION info;
1583 WCHAR *prop;
1584 BOOL rc;
1585 WCHAR *deformated;
1586 WCHAR *cmd;
1587 INT len;
1588 UINT prc;
1589 static const WCHAR spc[] = {' ',0};
1591 memset(&si,0,sizeof(STARTUPINFOW));
1592 memset(&info,0,sizeof(PROCESS_INFORMATION));
1594 prop = load_dynamic_property(package,source,&prc);
1595 if (!prop)
1596 return prc;
1598 deformat_string(package,target,&deformated);
1599 len = strlenW(prop) + strlenW(deformated) + 2;
1600 cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len);
1602 strcpyW(cmd,prop);
1603 strcatW(cmd,spc);
1604 strcatW(cmd,deformated);
1606 HeapFree(GetProcessHeap(),0,deformated);
1608 TRACE("executing exe %s \n",debugstr_w(cmd));
1610 rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
1611 c_collen, &si, &info);
1613 HeapFree(GetProcessHeap(),0,cmd);
1615 if ( !rc )
1617 ERR("Unable to execute command\n");
1618 return ERROR_SUCCESS;
1621 if (!(type & 0xc0))
1622 WaitForSingleObject(info.hProcess,INFINITE);
1624 CloseHandle( info.hProcess );
1625 CloseHandle( info.hThread );
1626 return ERROR_SUCCESS;
1629 static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source,
1630 const LPWSTR target, const INT type)
1632 LPWSTR filename, deformated;
1633 STARTUPINFOW si;
1634 PROCESS_INFORMATION info;
1635 BOOL rc;
1637 memset(&si,0,sizeof(STARTUPINFOW));
1639 filename = resolve_folder(package, source, FALSE, FALSE, NULL);
1641 if (!filename)
1642 return ERROR_FUNCTION_FAILED;
1644 SetCurrentDirectoryW(filename);
1645 HeapFree(GetProcessHeap(),0,filename);
1647 deformat_string(package,target,&deformated);
1649 TRACE("executing exe %s \n",debugstr_w(deformated));
1651 rc = CreateProcessW(NULL, deformated, NULL, NULL, FALSE, 0, NULL,
1652 c_collen, &si, &info);
1653 HeapFree(GetProcessHeap(),0,deformated);
1655 if ( !rc )
1657 ERR("Unable to execute command\n");
1658 return ERROR_SUCCESS;
1661 if (!(type & 0xc0))
1662 WaitForSingleObject(info.hProcess,INFINITE);
1664 CloseHandle( info.hProcess );
1665 CloseHandle( info.hThread );
1666 return ERROR_SUCCESS;
1669 /***********************************************************************
1670 * create_full_pathW
1672 * Recursively create all directories in the path.
1674 * shamelessly stolen from setupapi/queue.c
1676 static BOOL create_full_pathW(const WCHAR *path)
1678 BOOL ret = TRUE;
1679 int len;
1680 WCHAR *new_path;
1682 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *
1683 sizeof(WCHAR));
1685 strcpyW(new_path, path);
1687 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
1688 new_path[len - 1] = 0;
1690 while(!CreateDirectoryW(new_path, NULL))
1692 WCHAR *slash;
1693 DWORD last_error = GetLastError();
1694 if(last_error == ERROR_ALREADY_EXISTS)
1695 break;
1697 if(last_error != ERROR_PATH_NOT_FOUND)
1699 ret = FALSE;
1700 break;
1703 if(!(slash = strrchrW(new_path, '\\')))
1705 ret = FALSE;
1706 break;
1709 len = slash - new_path;
1710 new_path[len] = 0;
1711 if(!create_full_pathW(new_path))
1713 ret = FALSE;
1714 break;
1716 new_path[len] = '\\';
1719 HeapFree(GetProcessHeap(), 0, new_path);
1720 return ret;
1724 * Also we cannot enable/disable components either, so for now I am just going
1725 * to do all the directories for all the components.
1727 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1729 static const WCHAR ExecSeqQuery[] = {
1730 's','e','l','e','c','t',' ','D','i','r','e','c','t','o','r','y','_',' ',
1731 'f','r','o','m',' ','C','r','e','a','t','e','F','o','l','d','e','r',0 };
1732 UINT rc;
1733 MSIQUERY *view;
1734 MSIFOLDER *folder;
1736 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1737 if (rc != ERROR_SUCCESS)
1738 return ERROR_SUCCESS;
1740 rc = MSI_ViewExecute(view, 0);
1741 if (rc != ERROR_SUCCESS)
1743 MSI_ViewClose(view);
1744 msiobj_release(&view->hdr);
1745 return rc;
1748 while (1)
1750 WCHAR dir[0x100];
1751 LPWSTR full_path;
1752 DWORD sz;
1753 MSIRECORD *row = NULL, *uirow;
1755 rc = MSI_ViewFetch(view,&row);
1756 if (rc != ERROR_SUCCESS)
1758 rc = ERROR_SUCCESS;
1759 break;
1762 sz=0x100;
1763 rc = MSI_RecordGetStringW(row,1,dir,&sz);
1765 if (rc!= ERROR_SUCCESS)
1767 ERR("Unable to get folder id \n");
1768 msiobj_release(&row->hdr);
1769 continue;
1772 sz = MAX_PATH;
1773 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1774 if (!full_path)
1776 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1777 msiobj_release(&row->hdr);
1778 continue;
1781 TRACE("Folder is %s\n",debugstr_w(full_path));
1783 /* UI stuff */
1784 uirow = MSI_CreateRecord(1);
1785 MSI_RecordSetStringW(uirow,1,full_path);
1786 ui_actiondata(package,szCreateFolders,uirow);
1787 msiobj_release( &uirow->hdr );
1789 if (folder->State == 0)
1790 create_full_pathW(full_path);
1792 folder->State = 3;
1794 msiobj_release(&row->hdr);
1795 HeapFree(GetProcessHeap(),0,full_path);
1797 MSI_ViewClose(view);
1798 msiobj_release(&view->hdr);
1800 return rc;
1803 static int load_component(MSIPACKAGE* package, MSIRECORD * row)
1805 int index = package->loaded_components;
1806 DWORD sz;
1808 /* fill in the data */
1810 package->loaded_components++;
1811 if (package->loaded_components == 1)
1812 package->components = HeapAlloc(GetProcessHeap(),0,
1813 sizeof(MSICOMPONENT));
1814 else
1815 package->components = HeapReAlloc(GetProcessHeap(),0,
1816 package->components, package->loaded_components *
1817 sizeof(MSICOMPONENT));
1819 memset(&package->components[index],0,sizeof(MSICOMPONENT));
1821 sz = 96;
1822 MSI_RecordGetStringW(row,1,package->components[index].Component,&sz);
1824 TRACE("Loading Component %s\n",
1825 debugstr_w(package->components[index].Component));
1827 sz = 0x100;
1828 if (!MSI_RecordIsNull(row,2))
1829 MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz);
1831 sz = 96;
1832 MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz);
1834 package->components[index].Attributes = MSI_RecordGetInteger(row,4);
1836 sz = 0x100;
1837 MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz);
1839 sz = 96;
1840 MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);
1842 package->components[index].Installed = INSTALLSTATE_ABSENT;
1843 package->components[index].Action = INSTALLSTATE_UNKNOWN;
1844 package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN;
1846 package->components[index].Enabled = TRUE;
1848 return index;
1851 static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
1853 int index = package->loaded_features;
1854 DWORD sz;
1855 static const WCHAR Query1[] = {'S','E','L','E','C','T',' ','C','o','m','p',
1856 'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',
1857 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',
1858 'a','t','u','r','e','_','=','\'','%','s','\'',0};
1859 static const WCHAR Query2[] = {'S','E','L','E','C','T',' ','*',' ','F','R',
1860 'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',
1861 'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};
1862 MSIQUERY * view;
1863 MSIQUERY * view2;
1864 MSIRECORD * row2;
1865 MSIRECORD * row3;
1866 UINT rc;
1868 /* fill in the data */
1870 package->loaded_features ++;
1871 if (package->loaded_features == 1)
1872 package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE));
1873 else
1874 package->features = HeapReAlloc(GetProcessHeap(),0,package->features,
1875 package->loaded_features * sizeof(MSIFEATURE));
1877 memset(&package->features[index],0,sizeof(MSIFEATURE));
1879 sz = 96;
1880 MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz);
1882 TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature));
1884 sz = 96;
1885 if (!MSI_RecordIsNull(row,2))
1886 MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz);
1888 sz = 0x100;
1889 if (!MSI_RecordIsNull(row,3))
1890 MSI_RecordGetStringW(row,3,package->features[index].Title,&sz);
1892 sz = 0x100;
1893 if (!MSI_RecordIsNull(row,4))
1894 MSI_RecordGetStringW(row,4,package->features[index].Description,&sz);
1896 if (!MSI_RecordIsNull(row,5))
1897 package->features[index].Display = MSI_RecordGetInteger(row,5);
1899 package->features[index].Level= MSI_RecordGetInteger(row,6);
1901 sz = 96;
1902 if (!MSI_RecordIsNull(row,7))
1903 MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);
1905 package->features[index].Attributes= MSI_RecordGetInteger(row,8);
1907 package->features[index].Installed = INSTALLSTATE_ABSENT;
1908 package->features[index].Action = INSTALLSTATE_UNKNOWN;
1909 package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN;
1911 /* load feature components */
1913 rc = ACTION_OpenQuery(package->db, &view, Query1, package->features[index].Feature);
1914 if (rc != ERROR_SUCCESS)
1915 return;
1916 rc = MSI_ViewExecute(view,0);
1917 if (rc != ERROR_SUCCESS)
1919 MSI_ViewClose(view);
1920 msiobj_release(&view->hdr);
1921 return;
1923 while (1)
1925 DWORD sz = 0x100;
1926 WCHAR buffer[0x100];
1927 DWORD rc;
1928 INT c_indx;
1929 INT cnt = package->features[index].ComponentCount;
1931 rc = MSI_ViewFetch(view,&row2);
1932 if (rc != ERROR_SUCCESS)
1933 break;
1935 sz = 0x100;
1936 MSI_RecordGetStringW(row2,1,buffer,&sz);
1938 /* check to see if the component is already loaded */
1939 c_indx = get_loaded_component(package,buffer);
1940 if (c_indx != -1)
1942 TRACE("Component %s already loaded at %i\n", debugstr_w(buffer),
1943 c_indx);
1944 package->features[index].Components[cnt] = c_indx;
1945 package->features[index].ComponentCount ++;
1948 rc = ACTION_OpenQuery(package->db, &view2, Query2, buffer);
1949 if (rc != ERROR_SUCCESS)
1951 msiobj_release( &row2->hdr );
1952 continue;
1954 rc = MSI_ViewExecute(view2,0);
1955 if (rc != ERROR_SUCCESS)
1957 msiobj_release( &row2->hdr );
1958 MSI_ViewClose(view2);
1959 msiobj_release( &view2->hdr );
1960 continue;
1962 while (1)
1964 DWORD rc;
1966 rc = MSI_ViewFetch(view2,&row3);
1967 if (rc != ERROR_SUCCESS)
1968 break;
1969 c_indx = load_component(package,row3);
1970 msiobj_release( &row3->hdr );
1972 package->features[index].Components[cnt] = c_indx;
1973 package->features[index].ComponentCount ++;
1975 MSI_ViewClose(view2);
1976 msiobj_release( &view2->hdr );
1977 msiobj_release( &row2->hdr );
1979 MSI_ViewClose(view);
1980 msiobj_release(&view->hdr);
1984 * I am not doing any of the costing functionality yet.
1985 * Mostly looking at doing the Component and Feature loading
1987 * The native MSI does ALOT of modification to tables here. Mostly adding alot
1988 * of temporary columns to the Feature and Component tables.
1990 * note: native msi also tracks the short filename. but I am only going to
1991 * track the long ones. Also looking at this directory table
1992 * it appears that the directory table does not get the parents
1993 * resolved base on property only based on their entrys in the
1994 * directory table.
1996 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1998 MSIQUERY * view;
1999 MSIRECORD * row;
2000 UINT rc;
2001 static const WCHAR Query_all[] = {
2002 'S','E','L','E','C','T',' ','*',' ',
2003 'F','R','O','M',' ','F','e','a','t','u','r','e',0};
2004 static const WCHAR szCosting[] = {
2005 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2006 static const WCHAR szZero[] = { '0', 0 };
2008 MSI_SetPropertyW(package, szCosting, szZero);
2009 MSI_SetPropertyW(package, cszRootDrive , c_collen);
2011 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
2012 if (rc != ERROR_SUCCESS)
2013 return rc;
2014 rc = MSI_ViewExecute(view,0);
2015 if (rc != ERROR_SUCCESS)
2017 MSI_ViewClose(view);
2018 msiobj_release(&view->hdr);
2019 return rc;
2021 while (1)
2023 DWORD rc;
2025 rc = MSI_ViewFetch(view,&row);
2026 if (rc != ERROR_SUCCESS)
2027 break;
2029 load_feature(package,row);
2030 msiobj_release(&row->hdr);
2032 MSI_ViewClose(view);
2033 msiobj_release(&view->hdr);
2035 return ERROR_SUCCESS;
2038 static UINT load_file(MSIPACKAGE* package, MSIRECORD * row)
2040 DWORD index = package->loaded_files;
2041 DWORD i;
2042 LPWSTR buffer;
2044 /* fill in the data */
2046 package->loaded_files++;
2047 if (package->loaded_files== 1)
2048 package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
2049 else
2050 package->files = HeapReAlloc(GetProcessHeap(),0,
2051 package->files , package->loaded_files * sizeof(MSIFILE));
2053 memset(&package->files[index],0,sizeof(MSIFILE));
2055 package->files[index].File = load_dynamic_stringW(row, 1);
2056 buffer = load_dynamic_stringW(row, 2);
2058 package->files[index].ComponentIndex = -1;
2059 for (i = 0; i < package->loaded_components; i++)
2060 if (strcmpW(package->components[i].Component,buffer)==0)
2062 package->files[index].ComponentIndex = i;
2063 break;
2065 if (package->files[index].ComponentIndex == -1)
2066 ERR("Unfound Component %s\n",debugstr_w(buffer));
2067 HeapFree(GetProcessHeap(), 0, buffer);
2069 package->files[index].FileName = load_dynamic_stringW(row,3);
2071 reduce_to_longfilename(package->files[index].FileName);
2073 package->files[index].FileSize = MSI_RecordGetInteger(row,4);
2074 package->files[index].Version = load_dynamic_stringW(row, 5);
2075 package->files[index].Language = load_dynamic_stringW(row, 6);
2076 package->files[index].Attributes= MSI_RecordGetInteger(row,7);
2077 package->files[index].Sequence= MSI_RecordGetInteger(row,8);
2079 package->files[index].Temporary = FALSE;
2080 package->files[index].State = 0;
2082 TRACE("File Loaded (%s)\n",debugstr_w(package->files[index].File));
2084 return ERROR_SUCCESS;
2087 static UINT ACTION_FileCost(MSIPACKAGE *package)
2089 MSIQUERY * view;
2090 MSIRECORD * row;
2091 UINT rc;
2092 static const WCHAR Query[] = {
2093 'S','E','L','E','C','T',' ','*',' ',
2094 'F','R','O','M',' ','F','i','l','e',' ',
2095 'O','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e', 0};
2097 if (!package)
2098 return ERROR_INVALID_HANDLE;
2100 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2101 if (rc != ERROR_SUCCESS)
2102 return ERROR_SUCCESS;
2104 rc = MSI_ViewExecute(view, 0);
2105 if (rc != ERROR_SUCCESS)
2107 MSI_ViewClose(view);
2108 msiobj_release(&view->hdr);
2109 return ERROR_SUCCESS;
2112 while (1)
2114 rc = MSI_ViewFetch(view,&row);
2115 if (rc != ERROR_SUCCESS)
2117 rc = ERROR_SUCCESS;
2118 break;
2120 load_file(package,row);
2121 msiobj_release(&row->hdr);
2123 MSI_ViewClose(view);
2124 msiobj_release(&view->hdr);
2126 return ERROR_SUCCESS;
2129 static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)
2132 static const WCHAR Query[] =
2133 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',
2134 't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',
2135 'o','r','y','`',' ','=',' ','`','%','s','`',0};
2136 UINT rc;
2137 MSIQUERY * view;
2138 LPWSTR targetdir, parent, srcdir;
2139 MSIRECORD * row = 0;
2140 INT index = -1;
2141 DWORD i;
2143 TRACE("Looking for dir %s\n",debugstr_w(dir));
2145 for (i = 0; i < package->loaded_folders; i++)
2147 if (strcmpW(package->folders[i].Directory,dir)==0)
2149 TRACE(" %s retuning on index %lu\n",debugstr_w(dir),i);
2150 return i;
2154 TRACE("Working to load %s\n",debugstr_w(dir));
2156 index = package->loaded_folders++;
2157 if (package->loaded_folders==1)
2158 package->folders = HeapAlloc(GetProcessHeap(),0,
2159 sizeof(MSIFOLDER));
2160 else
2161 package->folders= HeapReAlloc(GetProcessHeap(),0,
2162 package->folders, package->loaded_folders*
2163 sizeof(MSIFOLDER));
2165 memset(&package->folders[index],0,sizeof(MSIFOLDER));
2167 package->folders[index].Directory = dupstrW(dir);
2169 rc = ACTION_OpenQuery(package->db, &view, Query, dir);
2170 if (rc != ERROR_SUCCESS)
2171 return -1;
2173 rc = MSI_ViewExecute(view, 0);
2174 if (rc != ERROR_SUCCESS)
2176 MSI_ViewClose(view);
2177 msiobj_release(&view->hdr);
2178 return -1;
2181 rc = MSI_ViewFetch(view,&row);
2182 if (rc != ERROR_SUCCESS)
2184 MSI_ViewClose(view);
2185 msiobj_release(&view->hdr);
2186 return -1;
2189 targetdir = load_dynamic_stringW(row,3);
2191 /* split src and target dir */
2192 if (strchrW(targetdir,':'))
2194 srcdir=strchrW(targetdir,':');
2195 *srcdir=0;
2196 srcdir ++;
2198 else
2199 srcdir=NULL;
2201 /* for now only pick long filename versions */
2202 if (strchrW(targetdir,'|'))
2204 targetdir = strchrW(targetdir,'|');
2205 *targetdir = 0;
2206 targetdir ++;
2208 if (srcdir && strchrW(srcdir,'|'))
2210 srcdir= strchrW(srcdir,'|');
2211 *srcdir= 0;
2212 srcdir ++;
2215 /* now check for root dirs */
2216 if (targetdir[0] == '.' && targetdir[1] == 0)
2217 targetdir = NULL;
2219 if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
2220 srcdir = NULL;
2222 if (targetdir)
2224 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
2225 if (package->folders[index].TargetDefault)
2226 HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault);
2227 package->folders[index].TargetDefault = dupstrW(targetdir);
2230 if (srcdir)
2231 package->folders[index].SourceDefault = dupstrW(srcdir);
2232 else if (targetdir)
2233 package->folders[index].SourceDefault = dupstrW(targetdir);
2234 HeapFree(GetProcessHeap(), 0, targetdir);
2236 parent = load_dynamic_stringW(row,2);
2237 if (parent)
2239 i = load_folder(package,parent);
2240 package->folders[index].ParentIndex = i;
2241 TRACE("Parent is index %i... %s %s\n",
2242 package->folders[index].ParentIndex,
2243 debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),
2244 debugstr_w(parent));
2246 else
2247 package->folders[index].ParentIndex = -2;
2248 HeapFree(GetProcessHeap(), 0, parent);
2250 package->folders[index].Property = load_dynamic_property(package, dir,NULL);
2252 msiobj_release(&row->hdr);
2253 MSI_ViewClose(view);
2254 msiobj_release(&view->hdr);
2255 TRACE(" %s retuning on index %i\n",debugstr_w(dir),index);
2256 return index;
2260 static LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name,
2261 BOOL source, BOOL set_prop, MSIFOLDER **folder)
2263 DWORD i;
2264 LPWSTR p, path = NULL;
2266 TRACE("Working to resolve %s\n",debugstr_w(name));
2268 /* special resolving for Target and Source root dir */
2269 if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
2271 if (!source)
2273 path = load_dynamic_property(package,cszTargetDir,NULL);
2274 if (!path)
2276 path = load_dynamic_property(package,cszRootDrive,NULL);
2277 if (set_prop)
2278 MSI_SetPropertyW(package,cszTargetDir,path);
2280 if (folder)
2281 *folder = &(package->folders[0]);
2282 return path;
2284 else
2286 path = load_dynamic_property(package,cszSourceDir,NULL);
2287 if (!path)
2289 path = load_dynamic_property(package,cszDatabase,NULL);
2290 if (path)
2292 p = strrchrW(path,'\\');
2293 if (p)
2294 *(p+1) = 0;
2297 if (folder)
2298 *folder = &(package->folders[0]);
2299 return path;
2303 for (i = 0; i < package->loaded_folders; i++)
2305 if (strcmpW(package->folders[i].Directory,name)==0)
2306 break;
2309 if (i >= package->loaded_folders)
2310 return NULL;
2312 if (folder)
2313 *folder = &(package->folders[i]);
2315 if (!source && package->folders[i].ResolvedTarget)
2317 path = dupstrW(package->folders[i].ResolvedTarget);
2318 TRACE(" already resolved to %s\n",debugstr_w(path));
2319 return path;
2321 else if (source && package->folders[i].ResolvedSource)
2323 path = dupstrW(package->folders[i].ResolvedSource);
2324 return path;
2326 else if (!source && package->folders[i].Property)
2328 path = dupstrW(package->folders[i].Property);
2329 TRACE(" internally set to %s\n",debugstr_w(path));
2330 if (set_prop)
2331 MSI_SetPropertyW(package,name,path);
2332 return path;
2335 if (package->folders[i].ParentIndex >= 0)
2337 LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;
2339 TRACE(" ! Parent is %s\n", debugstr_w(parent));
2341 p = resolve_folder(package, parent, source, set_prop, NULL);
2342 if (!source)
2344 TRACE(" TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault));
2345 path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL);
2346 package->folders[i].ResolvedTarget = dupstrW(path);
2347 TRACE(" resolved into %s\n",debugstr_w(path));
2348 if (set_prop)
2349 MSI_SetPropertyW(package,name,path);
2351 else
2353 path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);
2354 package->folders[i].ResolvedSource = dupstrW(path);
2356 HeapFree(GetProcessHeap(),0,p);
2358 return path;
2361 static UINT SetFeatureStates(MSIPACKAGE *package)
2363 LPWSTR level;
2364 INT install_level;
2365 DWORD i;
2366 INT j;
2367 LPWSTR override = NULL;
2368 static const WCHAR all[]={'A','L','L',0};
2369 static const WCHAR szlevel[] = {
2370 'I','N','S','T','A','L','L','L','E','V','E','L',0};
2371 static const WCHAR szAddLocal[] = {
2372 'A','D','D','L','O','C','A','L',0};
2374 /* I do not know if this is where it should happen.. but */
2376 TRACE("Checking Install Level\n");
2378 level = load_dynamic_property(package,szlevel,NULL);
2379 if (level)
2381 install_level = atoiW(level);
2382 HeapFree(GetProcessHeap(), 0, level);
2384 else
2385 install_level = 1;
2387 /* ok hereis the rub
2388 * ADDLOCAL and its friend OVERRIDE INSTALLLEVLE
2389 * I have confirmed this if ADDLOCALis stated then the INSTALLLEVEL is
2390 * itnored for all the features. seems strange, epsecially since it is not
2391 * documented anywhere, but it is how it works.
2394 override = load_dynamic_property(package,szAddLocal,NULL);
2396 if (override)
2398 for(i = 0; i < package->loaded_features; i++)
2400 if (strcmpiW(override,all)==0 ||
2401 strstrW(override,package->features[i].Feature))
2403 package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
2404 package->features[i].Action = INSTALLSTATE_LOCAL;
2407 HeapFree(GetProcessHeap(),0,override);
2409 else
2411 for(i = 0; i < package->loaded_features; i++)
2413 BOOL feature_state= ((package->features[i].Level > 0) &&
2414 (package->features[i].Level <= install_level));
2416 if (feature_state)
2418 package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
2419 package->features[i].Action = INSTALLSTATE_LOCAL;
2425 * now we want to enable or disable components base on feature
2428 for(i = 0; i < package->loaded_features; i++)
2430 MSIFEATURE* feature = &package->features[i];
2431 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
2432 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2433 feature->ActionRequest);
2435 for( j = 0; j < feature->ComponentCount; j++)
2437 MSICOMPONENT* component = &package->components[
2438 feature->Components[j]];
2440 if (!component->Enabled)
2442 component->Action = INSTALLSTATE_ABSENT;
2443 component->ActionRequest = INSTALLSTATE_ABSENT;
2445 else
2447 if (feature->Action == INSTALLSTATE_LOCAL)
2448 component->Action = INSTALLSTATE_LOCAL;
2449 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
2450 component->ActionRequest = INSTALLSTATE_LOCAL;
2455 for(i = 0; i < package->loaded_components; i++)
2457 MSICOMPONENT* component= &package->components[i];
2459 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
2460 debugstr_w(component->Component), component->Installed,
2461 component->Action, component->ActionRequest);
2465 return ERROR_SUCCESS;
2469 * Alot is done in this function aside from just the costing.
2470 * The costing needs to be implemented at some point but for now I am going
2471 * to focus on the directory building
2474 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2476 static const WCHAR ExecSeqQuery[] = {
2477 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2478 'D','i','r','e','c','t','o','r','y',0};
2479 static const WCHAR ConditionQuery[] = {
2480 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2481 'C','o','n','d','i','t','i','o','n',0};
2482 static const WCHAR szCosting[] = {
2483 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2484 static const WCHAR szlevel[] = {
2485 'I','N','S','T','A','L','L','L','E','V','E','L',0};
2486 static const WCHAR szOne[] = { '1', 0 };
2487 UINT rc;
2488 MSIQUERY * view;
2489 DWORD i;
2490 LPWSTR level;
2492 TRACE("Building Directory properties\n");
2494 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2495 if (rc == ERROR_SUCCESS)
2497 rc = MSI_ViewExecute(view, 0);
2498 if (rc != ERROR_SUCCESS)
2500 MSI_ViewClose(view);
2501 msiobj_release(&view->hdr);
2502 return rc;
2505 while (1)
2507 WCHAR name[0x100];
2508 LPWSTR path;
2509 MSIRECORD * row = 0;
2510 DWORD sz;
2512 rc = MSI_ViewFetch(view,&row);
2513 if (rc != ERROR_SUCCESS)
2515 rc = ERROR_SUCCESS;
2516 break;
2519 sz=0x100;
2520 MSI_RecordGetStringW(row,1,name,&sz);
2522 /* This helper function now does ALL the work */
2523 TRACE("Dir %s ...\n",debugstr_w(name));
2524 load_folder(package,name);
2525 path = resolve_folder(package,name,FALSE,TRUE,NULL);
2526 TRACE("resolves to %s\n",debugstr_w(path));
2527 HeapFree( GetProcessHeap(), 0, path);
2529 msiobj_release(&row->hdr);
2531 MSI_ViewClose(view);
2532 msiobj_release(&view->hdr);
2535 TRACE("File calculations %i files\n",package->loaded_files);
2537 for (i = 0; i < package->loaded_files; i++)
2539 MSICOMPONENT* comp = NULL;
2540 MSIFILE* file= NULL;
2542 file = &package->files[i];
2543 if (file->ComponentIndex >= 0)
2544 comp = &package->components[file->ComponentIndex];
2546 if (file->Temporary == TRUE)
2547 continue;
2549 if (comp)
2551 LPWSTR p;
2553 /* calculate target */
2554 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
2556 if (file->TargetPath)
2557 HeapFree(GetProcessHeap(),0,file->TargetPath);
2559 TRACE("file %s is named %s\n",
2560 debugstr_w(file->File),debugstr_w(file->FileName));
2562 file->TargetPath = build_directory_name(2, p, file->FileName);
2564 HeapFree(GetProcessHeap(),0,p);
2566 TRACE("file %s resolves to %s\n",
2567 debugstr_w(file->File),debugstr_w(file->TargetPath));
2569 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2571 file->State = 1;
2572 comp->Cost += file->FileSize;
2574 else
2576 if (file->Version)
2578 DWORD handle;
2579 DWORD versize;
2580 UINT sz;
2581 LPVOID version;
2582 static const WCHAR name[] =
2583 {'\\',0};
2584 static const WCHAR name_fmt[] =
2585 {'%','u','.','%','u','.','%','u','.','%','u',0};
2586 WCHAR filever[0x100];
2587 VS_FIXEDFILEINFO *lpVer;
2589 FIXME("Version comparison.. \n");
2590 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
2591 version = HeapAlloc(GetProcessHeap(),0,versize);
2592 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
2594 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
2596 sprintfW(filever,name_fmt,
2597 HIWORD(lpVer->dwFileVersionMS),
2598 LOWORD(lpVer->dwFileVersionMS),
2599 HIWORD(lpVer->dwFileVersionLS),
2600 LOWORD(lpVer->dwFileVersionLS));
2602 TRACE("new %s old %s\n", debugstr_w(file->Version),
2603 debugstr_w(filever));
2604 if (strcmpiW(filever,file->Version)<0)
2606 file->State = 2;
2607 FIXME("cost should be diff in size\n");
2608 comp->Cost += file->FileSize;
2610 else
2611 file->State = 3;
2612 HeapFree(GetProcessHeap(),0,version);
2614 else
2615 file->State = 3;
2620 TRACE("Evaluating Condition Table\n");
2622 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2623 if (rc == ERROR_SUCCESS)
2625 rc = MSI_ViewExecute(view, 0);
2626 if (rc != ERROR_SUCCESS)
2628 MSI_ViewClose(view);
2629 msiobj_release(&view->hdr);
2630 return rc;
2633 while (1)
2635 WCHAR Feature[0x100];
2636 MSIRECORD * row = 0;
2637 DWORD sz;
2638 int feature_index;
2640 rc = MSI_ViewFetch(view,&row);
2642 if (rc != ERROR_SUCCESS)
2644 rc = ERROR_SUCCESS;
2645 break;
2648 sz = 0x100;
2649 MSI_RecordGetStringW(row,1,Feature,&sz);
2651 feature_index = get_loaded_feature(package,Feature);
2652 if (feature_index < 0)
2653 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));
2654 else
2656 LPWSTR Condition;
2657 Condition = load_dynamic_stringW(row,3);
2659 if (MSI_EvaluateConditionW(package,Condition) ==
2660 MSICONDITION_TRUE)
2662 int level = MSI_RecordGetInteger(row,2);
2663 TRACE("Reseting feature %s to level %i\n",
2664 debugstr_w(Feature), level);
2665 package->features[feature_index].Level = level;
2667 HeapFree(GetProcessHeap(),0,Condition);
2670 msiobj_release(&row->hdr);
2672 MSI_ViewClose(view);
2673 msiobj_release(&view->hdr);
2676 TRACE("Enabling or Disabling Components\n");
2677 for (i = 0; i < package->loaded_components; i++)
2679 if (package->components[i].Condition[0])
2681 if (MSI_EvaluateConditionW(package,
2682 package->components[i].Condition) == MSICONDITION_FALSE)
2684 TRACE("Disabling component %s\n",
2685 debugstr_w(package->components[i].Component));
2686 package->components[i].Enabled = FALSE;
2691 MSI_SetPropertyW(package,szCosting,szOne);
2692 /* set default run level if not set */
2693 level = load_dynamic_property(package,szlevel,NULL);
2694 if (!level)
2695 MSI_SetPropertyW(package,szlevel, szOne);
2696 else
2697 HeapFree(GetProcessHeap(),0,level);
2699 return SetFeatureStates(package);
2704 * This is a helper function for handling embedded cabinet media
2706 static UINT writeout_cabinet_stream(MSIPACKAGE *package, WCHAR* stream_name,
2707 WCHAR* source)
2709 UINT rc;
2710 USHORT* data;
2711 UINT size;
2712 DWORD write;
2713 HANDLE the_file;
2714 WCHAR tmp[MAX_PATH];
2716 rc = read_raw_stream_data(package->db,stream_name,&data,&size);
2717 if (rc != ERROR_SUCCESS)
2718 return rc;
2720 write = MAX_PATH;
2721 if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
2722 GetTempPathW(MAX_PATH,tmp);
2724 GetTempFileNameW(tmp,stream_name,0,source);
2726 track_tempfile(package,strrchrW(source,'\\'), source);
2727 the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2728 FILE_ATTRIBUTE_NORMAL, NULL);
2730 if (the_file == INVALID_HANDLE_VALUE)
2732 rc = ERROR_FUNCTION_FAILED;
2733 goto end;
2736 WriteFile(the_file,data,size,&write,NULL);
2737 CloseHandle(the_file);
2738 TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
2739 end:
2740 HeapFree(GetProcessHeap(),0,data);
2741 return rc;
2745 /* Support functions for FDI functions */
2746 typedef struct
2748 MSIPACKAGE* package;
2749 LPCSTR cab_path;
2750 } CabData;
2752 static void * cabinet_alloc(ULONG cb)
2754 return HeapAlloc(GetProcessHeap(), 0, cb);
2757 static void cabinet_free(void *pv)
2759 HeapFree(GetProcessHeap(), 0, pv);
2762 static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
2764 DWORD dwAccess = 0;
2765 DWORD dwShareMode = 0;
2766 DWORD dwCreateDisposition = OPEN_EXISTING;
2767 switch (oflag & _O_ACCMODE)
2769 case _O_RDONLY:
2770 dwAccess = GENERIC_READ;
2771 dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
2772 break;
2773 case _O_WRONLY:
2774 dwAccess = GENERIC_WRITE;
2775 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2776 break;
2777 case _O_RDWR:
2778 dwAccess = GENERIC_READ | GENERIC_WRITE;
2779 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2780 break;
2782 if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
2783 dwCreateDisposition = CREATE_NEW;
2784 else if (oflag & _O_CREAT)
2785 dwCreateDisposition = CREATE_ALWAYS;
2786 return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL, dwCreateDisposition, 0, NULL);
2789 static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
2791 DWORD dwRead;
2792 if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
2793 return dwRead;
2794 return 0;
2797 static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
2799 DWORD dwWritten;
2800 if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
2801 return dwWritten;
2802 return 0;
2805 static int cabinet_close(INT_PTR hf)
2807 return CloseHandle((HANDLE)hf) ? 0 : -1;
2810 static long cabinet_seek(INT_PTR hf, long dist, int seektype)
2812 /* flags are compatible and so are passed straight through */
2813 return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
2816 static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
2818 /* FIXME: try to do more processing in this function */
2819 switch (fdint)
2821 case fdintCOPY_FILE:
2823 CabData *data = (CabData*) pfdin->pv;
2824 ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
2825 char *file = cabinet_alloc((len+1)*sizeof(char));
2827 LPWSTR trackname;
2828 LPWSTR trackpath;
2829 LPWSTR tracknametmp;
2830 static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
2832 strcpy(file, data->cab_path);
2833 strcat(file, pfdin->psz1);
2835 TRACE("file: %s\n", debugstr_a(file));
2837 /* track this file so it can be deleted if not installed */
2838 trackpath=strdupAtoW(file);
2839 tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
2840 trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) +
2841 strlenW(tmpprefix)+1) * sizeof(WCHAR));
2843 strcpyW(trackname,tmpprefix);
2844 strcatW(trackname,tracknametmp);
2846 track_tempfile(data->package, trackname, trackpath);
2848 HeapFree(GetProcessHeap(),0,trackpath);
2849 HeapFree(GetProcessHeap(),0,trackname);
2850 HeapFree(GetProcessHeap(),0,tracknametmp);
2852 return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
2854 case fdintCLOSE_FILE_INFO:
2856 FILETIME ft;
2857 FILETIME ftLocal;
2858 if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
2859 return -1;
2860 if (!LocalFileTimeToFileTime(&ft, &ftLocal))
2861 return -1;
2862 if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
2863 return -1;
2865 cabinet_close(pfdin->hf);
2866 return 1;
2868 default:
2869 return 0;
2873 /***********************************************************************
2874 * extract_cabinet_file
2876 * Extract files from a cab file.
2878 static BOOL extract_cabinet_file(MSIPACKAGE* package, const WCHAR* source,
2879 const WCHAR* path)
2881 HFDI hfdi;
2882 ERF erf;
2883 BOOL ret;
2884 char *cabinet;
2885 char *cab_path;
2886 CabData data;
2888 TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));
2890 hfdi = FDICreate(cabinet_alloc,
2891 cabinet_free,
2892 cabinet_open,
2893 cabinet_read,
2894 cabinet_write,
2895 cabinet_close,
2896 cabinet_seek,
2898 &erf);
2899 if (!hfdi)
2901 ERR("FDICreate failed\n");
2902 return FALSE;
2905 if (!(cabinet = strdupWtoA( source )))
2907 FDIDestroy(hfdi);
2908 return FALSE;
2910 if (!(cab_path = strdupWtoA( path )))
2912 FDIDestroy(hfdi);
2913 HeapFree(GetProcessHeap(), 0, cabinet);
2914 return FALSE;
2917 data.package = package;
2918 data.cab_path = cab_path;
2920 ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
2922 if (!ret)
2923 ERR("FDICopy failed\n");
2925 FDIDestroy(hfdi);
2927 HeapFree(GetProcessHeap(), 0, cabinet);
2928 HeapFree(GetProcessHeap(), 0, cab_path);
2930 return ret;
2933 static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence,
2934 WCHAR* path)
2936 UINT rc;
2937 MSIQUERY * view;
2938 MSIRECORD * row = 0;
2939 WCHAR source[MAX_PATH];
2940 static const WCHAR ExecSeqQuery[] = {
2941 's','e','l','e','c','t',' ','*',' ',
2942 'f','r','o','m',' ','M','e','d','i','a',' ',
2943 'w','h','e','r','e',' ','L','a','s','t','S','e','q','u','e','n','c','e',' ','>','=',' ','%','i',' ',
2944 'o','r','d','e','r',' ','b','y',' ','L','a','s','t','S','e','q','u','e','n','c','e',0};
2945 WCHAR Query[1024];
2946 WCHAR cab[0x100];
2947 DWORD sz=0x100;
2948 INT seq;
2949 static UINT last_sequence = 0;
2951 if (sequence <= last_sequence)
2953 TRACE("Media already ready (%u, %u)\n",sequence,last_sequence);
2954 return ERROR_SUCCESS;
2957 sprintfW(Query,ExecSeqQuery,sequence);
2959 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2960 if (rc != ERROR_SUCCESS)
2961 return rc;
2963 rc = MSI_ViewExecute(view, 0);
2964 if (rc != ERROR_SUCCESS)
2966 MSI_ViewClose(view);
2967 msiobj_release(&view->hdr);
2968 return rc;
2971 rc = MSI_ViewFetch(view,&row);
2972 if (rc != ERROR_SUCCESS)
2974 MSI_ViewClose(view);
2975 msiobj_release(&view->hdr);
2976 return rc;
2978 seq = MSI_RecordGetInteger(row,2);
2979 last_sequence = seq;
2981 if (!MSI_RecordIsNull(row,4))
2983 sz=0x100;
2984 MSI_RecordGetStringW(row,4,cab,&sz);
2985 TRACE("Source is CAB %s\n",debugstr_w(cab));
2986 /* the stream does not contain the # character */
2987 if (cab[0]=='#')
2989 writeout_cabinet_stream(package,&cab[1],source);
2990 strcpyW(path,source);
2991 *(strrchrW(path,'\\')+1)=0;
2993 else
2995 sz = MAX_PATH;
2996 if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
2998 ERR("No Source dir defined \n");
2999 rc = ERROR_FUNCTION_FAILED;
3001 else
3003 strcpyW(path,source);
3004 strcatW(source,cab);
3005 /* extract the cab file into a folder in the temp folder */
3006 sz = MAX_PATH;
3007 if (MSI_GetPropertyW(package, cszTempFolder,path, &sz)
3008 != ERROR_SUCCESS)
3009 GetTempPathW(MAX_PATH,path);
3012 rc = !extract_cabinet_file(package, source,path);
3014 msiobj_release(&row->hdr);
3015 MSI_ViewClose(view);
3016 msiobj_release(&view->hdr);
3017 return rc;
3020 inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
3022 UINT rc;
3023 MSIFOLDER *folder;
3024 LPWSTR install_path;
3026 install_path = resolve_folder(package, package->components[component].Directory,
3027 FALSE, FALSE, &folder);
3028 if (!install_path)
3029 return ERROR_FUNCTION_FAILED;
3031 /* create the path */
3032 if (folder->State == 0)
3034 create_full_pathW(install_path);
3035 folder->State = 2;
3037 HeapFree(GetProcessHeap(), 0, install_path);
3039 return rc;
3042 static UINT ACTION_InstallFiles(MSIPACKAGE *package)
3044 UINT rc = ERROR_SUCCESS;
3045 DWORD index;
3046 MSIRECORD * uirow;
3047 WCHAR uipath[MAX_PATH];
3049 if (!package)
3050 return ERROR_INVALID_HANDLE;
3052 /* increment progress bar each time action data is sent */
3053 ui_progress(package,1,1,1,0);
3055 for (index = 0; index < package->loaded_files; index++)
3057 WCHAR path_to_source[MAX_PATH];
3058 MSIFILE *file;
3060 file = &package->files[index];
3062 if (file->Temporary)
3063 continue;
3065 if (package->components[file->ComponentIndex].ActionRequest !=
3066 INSTALLSTATE_LOCAL)
3068 TRACE("File %s is not scheduled for install\n",
3069 debugstr_w(file->File));
3071 continue;
3074 if ((file->State == 1) || (file->State == 2))
3076 TRACE("Installing %s\n",debugstr_w(file->File));
3077 rc = ready_media_for_file(package,file->Sequence,path_to_source);
3079 * WARNING!
3080 * our file table could change here because a new temp file
3081 * may have been created
3083 file = &package->files[index];
3084 if (rc != ERROR_SUCCESS)
3086 ERR("Unable to ready media\n");
3087 rc = ERROR_FUNCTION_FAILED;
3088 break;
3091 create_component_directory( package, file->ComponentIndex);
3093 strcpyW(file->SourcePath, path_to_source);
3094 strcatW(file->SourcePath, file->File);
3096 TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
3097 debugstr_w(file->TargetPath));
3099 /* the UI chunk */
3100 uirow=MSI_CreateRecord(9);
3101 MSI_RecordSetStringW(uirow,1,file->File);
3102 strcpyW(uipath,file->TargetPath);
3103 *(strrchrW(uipath,'\\')+1)=0;
3104 MSI_RecordSetStringW(uirow,9,uipath);
3105 MSI_RecordSetInteger(uirow,6,file->FileSize);
3106 ui_actiondata(package,szInstallFiles,uirow);
3107 msiobj_release( &uirow->hdr );
3109 if (!MoveFileW(file->SourcePath,file->TargetPath))
3111 rc = GetLastError();
3112 ERR("Unable to move file (%s -> %s) (error %d)\n",
3113 debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
3114 rc);
3115 if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
3117 CopyFileW(file->SourcePath,file->TargetPath,FALSE);
3118 DeleteFileW(file->SourcePath);
3119 rc = 0;
3121 else if (rc == ERROR_FILE_NOT_FOUND)
3123 ERR("Source File Not Found! Continueing\n");
3124 rc = 0;
3126 else
3128 ERR("Ignoring Error and continuing...\n");
3129 rc = 0;
3132 else
3133 file->State = 4;
3135 ui_progress(package,2,0,0,0);
3139 return rc;
3142 inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
3143 LPWSTR* file_source)
3145 DWORD index;
3147 if (!package)
3148 return ERROR_INVALID_HANDLE;
3150 for (index = 0; index < package->loaded_files; index ++)
3152 if (strcmpW(file_key,package->files[index].File)==0)
3154 if (package->files[index].State >= 3)
3156 *file_source = dupstrW(package->files[index].TargetPath);
3157 return ERROR_SUCCESS;
3159 else
3160 return ERROR_FILE_NOT_FOUND;
3164 return ERROR_FUNCTION_FAILED;
3167 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
3169 UINT rc;
3170 MSIQUERY * view;
3171 MSIRECORD * row = 0;
3172 static const WCHAR ExecSeqQuery[] = {
3173 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
3174 'D','u','p','l','i','c','a','t','e','F','i','l','e',0};
3176 if (!package)
3177 return ERROR_INVALID_HANDLE;
3179 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3180 if (rc != ERROR_SUCCESS)
3181 return ERROR_SUCCESS;
3183 rc = MSI_ViewExecute(view, 0);
3184 if (rc != ERROR_SUCCESS)
3186 MSI_ViewClose(view);
3187 msiobj_release(&view->hdr);
3188 return rc;
3191 while (1)
3193 WCHAR file_key[0x100];
3194 WCHAR *file_source = NULL;
3195 WCHAR dest_name[0x100];
3196 LPWSTR dest_path, dest;
3197 WCHAR component[0x100];
3198 INT component_index;
3200 DWORD sz=0x100;
3202 rc = MSI_ViewFetch(view,&row);
3203 if (rc != ERROR_SUCCESS)
3205 rc = ERROR_SUCCESS;
3206 break;
3209 sz=0x100;
3210 rc = MSI_RecordGetStringW(row,2,component,&sz);
3211 if (rc != ERROR_SUCCESS)
3213 ERR("Unable to get component\n");
3214 msiobj_release(&row->hdr);
3215 break;
3218 component_index = get_loaded_component(package,component);
3219 if (package->components[component_index].ActionRequest !=
3220 INSTALLSTATE_LOCAL)
3222 TRACE("Skipping copy due to disabled component\n");
3223 msiobj_release(&row->hdr);
3224 continue;
3227 sz=0x100;
3228 rc = MSI_RecordGetStringW(row,3,file_key,&sz);
3229 if (rc != ERROR_SUCCESS)
3231 ERR("Unable to get file key\n");
3232 msiobj_release(&row->hdr);
3233 break;
3236 rc = get_file_target(package,file_key,&file_source);
3238 if (rc != ERROR_SUCCESS)
3240 ERR("Original file unknown %s\n",debugstr_w(file_key));
3241 msiobj_release(&row->hdr);
3242 if (file_source)
3243 HeapFree(GetProcessHeap(),0,file_source);
3244 break;
3247 if (MSI_RecordIsNull(row,4))
3249 strcpyW(dest_name,strrchrW(file_source,'\\')+1);
3251 else
3253 sz=0x100;
3254 MSI_RecordGetStringW(row,4,dest_name,&sz);
3255 reduce_to_longfilename(dest_name);
3258 if (MSI_RecordIsNull(row,5))
3260 LPWSTR p;
3261 dest_path = dupstrW(file_source);
3262 p = strrchrW(dest_path,'\\');
3263 if (p)
3264 *p=0;
3266 else
3268 WCHAR destkey[0x100];
3269 sz=0x100;
3270 MSI_RecordGetStringW(row,5,destkey,&sz);
3271 sz = 0x100;
3272 dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
3273 if (!dest_path)
3275 ERR("Unable to get destination folder\n");
3276 msiobj_release(&row->hdr);
3277 if (file_source)
3278 HeapFree(GetProcessHeap(),0,file_source);
3279 break;
3283 dest = build_directory_name(2, dest_path, dest_name);
3284 HeapFree(GetProcessHeap(), 0, dest_path);
3286 TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
3287 debugstr_w(dest));
3289 if (strcmpW(file_source,dest))
3290 rc = !CopyFileW(file_source,dest,TRUE);
3291 else
3292 rc = ERROR_SUCCESS;
3294 if (rc != ERROR_SUCCESS)
3295 ERR("Failed to copy file\n");
3297 FIXME("We should track these duplicate files as well\n");
3299 msiobj_release(&row->hdr);
3300 HeapFree(GetProcessHeap(),0,dest);
3301 HeapFree(GetProcessHeap(),0,file_source);
3303 MSI_ViewClose(view);
3304 msiobj_release(&view->hdr);
3305 return rc;
3309 /* OK this value is "interpretted" and then formatted based on the
3310 first few characters */
3311 static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type,
3312 DWORD *size)
3314 LPSTR data = NULL;
3315 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
3317 if (value[1]=='x')
3319 LPWSTR ptr;
3320 CHAR byte[5];
3321 LPWSTR deformated;
3322 int count;
3324 deformat_string(package, &value[2], &deformated);
3326 /* binary value type */
3327 ptr = deformated;
3328 *type=REG_BINARY;
3329 *size = strlenW(ptr)/2;
3330 data = HeapAlloc(GetProcessHeap(),0,*size);
3332 byte[0] = '0';
3333 byte[1] = 'x';
3334 byte[4] = 0;
3335 count = 0;
3336 while (*ptr)
3338 byte[2]= *ptr;
3339 ptr++;
3340 byte[3]= *ptr;
3341 ptr++;
3342 data[count] = (BYTE)strtol(byte,NULL,0);
3343 count ++;
3345 HeapFree(GetProcessHeap(),0,deformated);
3347 TRACE("Data %li bytes(%i)\n",*size,count);
3349 else
3351 LPWSTR deformated;
3352 deformat_string(package, &value[1], &deformated);
3354 *type=REG_DWORD;
3355 *size = sizeof(DWORD);
3356 data = HeapAlloc(GetProcessHeap(),0,*size);
3357 *(LPDWORD)data = atoiW(deformated);
3358 TRACE("DWORD %i\n",*data);
3360 HeapFree(GetProcessHeap(),0,deformated);
3363 else
3365 WCHAR *ptr;
3366 *type=REG_SZ;
3368 if (value[0]=='#')
3370 if (value[1]=='%')
3372 ptr = &value[2];
3373 *type=REG_EXPAND_SZ;
3375 else
3376 ptr = &value[1];
3378 else
3379 ptr=value;
3381 *size = deformat_string(package, ptr,(LPWSTR*)&data);
3383 return data;
3386 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
3388 UINT rc;
3389 MSIQUERY * view;
3390 MSIRECORD * row = 0;
3391 static const WCHAR ExecSeqQuery[] = {
3392 's','e','l','e','c','t',' ','*',' ',
3393 'f','r','o','m',' ','R','e','g','i','s','t','r','y',0 };
3395 if (!package)
3396 return ERROR_INVALID_HANDLE;
3398 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3399 if (rc != ERROR_SUCCESS)
3400 return ERROR_SUCCESS;
3402 rc = MSI_ViewExecute(view, 0);
3403 if (rc != ERROR_SUCCESS)
3405 MSI_ViewClose(view);
3406 msiobj_release(&view->hdr);
3407 return rc;
3410 /* increment progress bar each time action data is sent */
3411 ui_progress(package,1,1,1,0);
3413 while (1)
3415 static const WCHAR szHCR[] =
3416 {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T','\\',0};
3417 static const WCHAR szHCU[] =
3418 {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',0};
3419 static const WCHAR szHLM[] =
3420 {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',
3421 '\\',0};
3422 static const WCHAR szHU[] =
3423 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
3425 LPSTR value_data = NULL;
3426 HKEY root_key, hkey;
3427 DWORD type,size;
3428 LPWSTR value, key, name, component;
3429 LPCWSTR szRoot;
3430 INT component_index;
3431 MSIRECORD * uirow;
3432 LPWSTR uikey;
3433 INT root;
3435 rc = MSI_ViewFetch(view,&row);
3436 if (rc != ERROR_SUCCESS)
3438 rc = ERROR_SUCCESS;
3439 break;
3442 value = NULL;
3443 key = NULL;
3444 uikey = NULL;
3445 name = NULL;
3447 component = load_dynamic_stringW(row, 6);
3448 component_index = get_loaded_component(package,component);
3450 if (package->components[component_index].ActionRequest !=
3451 INSTALLSTATE_LOCAL)
3453 TRACE("Skipping write due to disabled component\n");
3454 msiobj_release(&row->hdr);
3455 goto next;
3458 /* null values have special meanings during uninstalls and such */
3460 if(MSI_RecordIsNull(row,5))
3462 msiobj_release(&row->hdr);
3463 goto next;
3466 root = MSI_RecordGetInteger(row,2);
3467 key = load_dynamic_stringW(row, 3);
3469 name = load_dynamic_stringW(row, 4);
3471 /* get the root key */
3472 switch (root)
3474 case 0: root_key = HKEY_CLASSES_ROOT;
3475 szRoot = szHCR;
3476 break;
3477 case 1: root_key = HKEY_CURRENT_USER;
3478 szRoot = szHCU;
3479 break;
3480 case 2: root_key = HKEY_LOCAL_MACHINE;
3481 szRoot = szHLM;
3482 break;
3483 case 3: root_key = HKEY_USERS;
3484 szRoot = szHU;
3485 break;
3486 default:
3487 ERR("Unknown root %i\n",root);
3488 root_key=NULL;
3489 szRoot = NULL;
3490 break;
3492 if (!root_key)
3494 msiobj_release(&row->hdr);
3495 goto next;
3498 size = strlenW(key) + strlenW(szRoot) + 1;
3499 uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
3500 strcpyW(uikey,szRoot);
3501 strcatW(uikey,key);
3502 if (RegCreateKeyW( root_key, key, &hkey))
3504 ERR("Could not create key %s\n",debugstr_w(key));
3505 msiobj_release(&row->hdr);
3506 goto next;
3509 value = load_dynamic_stringW(row,5);
3510 value_data = parse_value(package, value, &type, &size);
3512 if (value_data)
3514 TRACE("Setting value %s\n",debugstr_w(name));
3515 RegSetValueExW(hkey, name, 0, type, value_data, size);
3517 uirow = MSI_CreateRecord(3);
3518 MSI_RecordSetStringW(uirow,2,name);
3519 MSI_RecordSetStringW(uirow,1,uikey);
3521 if (type == REG_SZ)
3522 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
3523 else
3524 MSI_RecordSetStringW(uirow,3,value);
3526 ui_actiondata(package,szWriteRegistryValues,uirow);
3527 ui_progress(package,2,0,0,0);
3528 msiobj_release( &uirow->hdr );
3530 HeapFree(GetProcessHeap(),0,value_data);
3532 HeapFree(GetProcessHeap(),0,value);
3534 msiobj_release(&row->hdr);
3535 RegCloseKey(hkey);
3536 next:
3537 if (uikey)
3538 HeapFree(GetProcessHeap(),0,uikey);
3539 if (key)
3540 HeapFree(GetProcessHeap(),0,key);
3541 if (name)
3542 HeapFree(GetProcessHeap(),0,name);
3543 if (component)
3544 HeapFree(GetProcessHeap(),0,component);
3546 MSI_ViewClose(view);
3547 msiobj_release(&view->hdr);
3548 return rc;
3552 * This helper function should probably go alot of places
3554 * Thinking about this, maybe this should become yet another Bison file
3556 static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data)
3558 WCHAR* mark=NULL;
3559 DWORD size=0;
3560 DWORD chunk=0;
3561 WCHAR key[0x100];
3562 LPWSTR value;
3563 DWORD sz;
3564 UINT rc;
3566 if (ptr==NULL)
3568 TRACE("Deformatting NULL string\n");
3569 *data = NULL;
3570 return 0;
3572 /* scan for special characters */
3573 if (!strchrW(ptr,'[') || (strchrW(ptr,'[') && !strchrW(ptr,']')))
3575 /* not formatted */
3576 size = (strlenW(ptr)+1) * sizeof(WCHAR);
3577 *data = HeapAlloc(GetProcessHeap(),0,size);
3578 strcpyW(*data,ptr);
3579 return size;
3582 /* formatted string located */
3583 mark = strchrW(ptr,'[');
3584 if (mark != ptr)
3586 INT cnt = (mark - ptr);
3587 TRACE("%i (%i) characters before marker\n",cnt,(mark-ptr));
3588 size = cnt * sizeof(WCHAR);
3589 size += sizeof(WCHAR);
3590 *data = HeapAlloc(GetProcessHeap(),0,size);
3591 strncpyW(*data,ptr,cnt);
3592 (*data)[cnt]=0;
3594 else
3596 size = sizeof(WCHAR);
3597 *data = HeapAlloc(GetProcessHeap(),0,size);
3598 (*data)[0]=0;
3600 mark++;
3601 strcpyW(key,mark);
3602 *strchrW(key,']')=0;
3603 mark = strchrW(mark,']');
3604 mark++;
3605 TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
3606 sz = 0;
3607 rc = MSI_GetPropertyW(package, key, NULL, &sz);
3608 if ((rc == ERROR_SUCCESS) || (rc == ERROR_MORE_DATA))
3610 LPWSTR newdata;
3612 sz++;
3613 value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
3614 MSI_GetPropertyW(package, key, value, &sz);
3616 chunk = (strlenW(value)+1) * sizeof(WCHAR);
3617 size+=chunk;
3618 newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
3619 *data = newdata;
3620 strcatW(*data,value);
3622 TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
3623 if (*mark!=0)
3625 LPWSTR newdata;
3626 chunk = (strlenW(mark)+1) * sizeof(WCHAR);
3627 size+=chunk;
3628 newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
3629 *data = newdata;
3630 strcatW(*data,mark);
3632 (*data)[strlenW(*data)]=0;
3633 TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
3635 /* recursively do this to clean up */
3636 mark = HeapAlloc(GetProcessHeap(),0,size);
3637 strcpyW(mark,*data);
3638 TRACE("String at this point %s\n",debugstr_w(mark));
3639 size = deformat_string(package,mark,data);
3640 HeapFree(GetProcessHeap(),0,mark);
3641 return size;
3644 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3646 return ERROR_SUCCESS;
3650 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3652 DWORD progress = 0;
3653 static const WCHAR q1[]={
3654 'S','E','L','E','C','T',' ','*',' ',
3655 'F','R','O','M',' ','R','e','g','i','s','t','r','y',0};
3656 UINT rc;
3657 MSIQUERY * view;
3658 MSIRECORD * row = 0;
3660 TRACE(" InstallValidate \n");
3662 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3663 if (rc != ERROR_SUCCESS)
3664 return ERROR_SUCCESS;
3666 rc = MSI_ViewExecute(view, 0);
3667 if (rc != ERROR_SUCCESS)
3669 MSI_ViewClose(view);
3670 msiobj_release(&view->hdr);
3671 return rc;
3673 while (1)
3675 rc = MSI_ViewFetch(view,&row);
3676 if (rc != ERROR_SUCCESS)
3678 rc = ERROR_SUCCESS;
3679 break;
3681 progress +=1;
3683 msiobj_release(&row->hdr);
3685 MSI_ViewClose(view);
3686 msiobj_release(&view->hdr);
3688 ui_progress(package,0,progress+package->loaded_files,0,0);
3690 return ERROR_SUCCESS;
3693 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3695 UINT rc;
3696 MSIQUERY * view = NULL;
3697 MSIRECORD * row = 0;
3698 static const WCHAR ExecSeqQuery[] = {
3699 'S','E','L','E','C','T',' ','*',' ',
3700 'f','r','o','m',' ','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n',0};
3701 static const WCHAR title[]=
3702 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3704 TRACE("Checking launch conditions\n");
3706 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3707 if (rc != ERROR_SUCCESS)
3708 return ERROR_SUCCESS;
3710 rc = MSI_ViewExecute(view, 0);
3711 if (rc != ERROR_SUCCESS)
3713 MSI_ViewClose(view);
3714 msiobj_release(&view->hdr);
3715 return rc;
3718 rc = ERROR_SUCCESS;
3719 while (rc == ERROR_SUCCESS)
3721 LPWSTR cond = NULL;
3722 LPWSTR message = NULL;
3724 rc = MSI_ViewFetch(view,&row);
3725 if (rc != ERROR_SUCCESS)
3727 rc = ERROR_SUCCESS;
3728 break;
3731 cond = load_dynamic_stringW(row,1);
3733 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
3735 message = load_dynamic_stringW(row,2);
3736 MessageBoxW(NULL,message,title,MB_OK);
3737 HeapFree(GetProcessHeap(),0,message);
3738 rc = ERROR_FUNCTION_FAILED;
3740 HeapFree(GetProcessHeap(),0,cond);
3741 msiobj_release(&row->hdr);
3743 MSI_ViewClose(view);
3744 msiobj_release(&view->hdr);
3745 return rc;
3748 static LPWSTR resolve_keypath( MSIPACKAGE* package, INT
3749 component_index)
3751 MSICOMPONENT* cmp = &package->components[component_index];
3753 if (cmp->KeyPath[0]==0)
3755 LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
3756 return p;
3758 if ((cmp->Attributes & 0x4) || (cmp->Attributes & 0x20))
3760 FIXME("UNIMPLEMENTED keypath as Registry or ODBC Source\n");
3761 return NULL;
3763 else
3765 int j;
3766 j = get_loaded_file(package,cmp->KeyPath);
3768 if (j>=0)
3770 LPWSTR p = dupstrW(package->files[j].TargetPath);
3771 return p;
3774 return NULL;
3778 * Ok further analysis makes me think that this work is
3779 * actually done in the PublishComponents and PublishFeatures
3780 * step, and not here. It appears like the keypath and all that is
3781 * resolved in this step, however actually written in the Publish steps.
3782 * But we will leave it here for now because it is unclear
3784 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3786 LPWSTR productcode;
3787 WCHAR squished_pc[0x100];
3788 WCHAR squished_cc[0x100];
3789 UINT rc;
3790 DWORD i;
3791 HKEY hkey=0,hkey2=0,hkey3=0;
3792 static const WCHAR szProductCode[]=
3793 {'P','r','o','d','u','c','t','C','o','d','e',0};
3794 static const WCHAR szInstaller[] = {
3795 'S','o','f','t','w','a','r','e','\\',
3796 'M','i','c','r','o','s','o','f','t','\\',
3797 'W','i','n','d','o','w','s','\\',
3798 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3799 'I','n','s','t','a','l','l','e','r',0 };
3800 static const WCHAR szFeatures[] = {
3801 'F','e','a','t','u','r','e','s',0 };
3802 static const WCHAR szComponents[] = {
3803 'C','o','m','p','o','n','e','n','t','s',0 };
3805 if (!package)
3806 return ERROR_INVALID_HANDLE;
3808 /* writes the Component and Features values to the registry */
3809 productcode = load_dynamic_property(package,szProductCode,&rc);
3810 if (!productcode)
3811 return rc;
3813 squash_guid(productcode,squished_pc);
3814 rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller,&hkey);
3815 if (rc != ERROR_SUCCESS)
3816 goto end;
3818 rc = RegCreateKeyW(hkey,szFeatures,&hkey2);
3819 if (rc != ERROR_SUCCESS)
3820 goto end;
3822 rc = RegCreateKeyW(hkey2,squished_pc,&hkey3);
3823 if (rc != ERROR_SUCCESS)
3824 goto end;
3826 /* here the guids are base 85 encoded */
3827 for (i = 0; i < package->loaded_features; i++)
3829 LPWSTR data = NULL;
3830 GUID clsid;
3831 int j;
3832 INT size;
3834 size = package->features[i].ComponentCount*21*sizeof(WCHAR);
3835 data = HeapAlloc(GetProcessHeap(), 0, size);
3837 data[0] = 0;
3838 for (j = 0; j < package->features[i].ComponentCount; j++)
3840 WCHAR buf[21];
3841 TRACE("From %s\n",debugstr_w(package->components
3842 [package->features[i].Components[j]].ComponentId));
3843 CLSIDFromString(package->components
3844 [package->features[i].Components[j]].ComponentId,
3845 &clsid);
3846 encode_base85_guid(&clsid,buf);
3847 TRACE("to %s\n",debugstr_w(buf));
3848 strcatW(data,buf);
3851 size = strlenW(data)*sizeof(WCHAR);
3852 RegSetValueExW(hkey3,package->features[i].Feature,0,REG_SZ,
3853 (LPSTR)data,size);
3854 HeapFree(GetProcessHeap(),0,data);
3857 RegCloseKey(hkey3);
3858 RegCloseKey(hkey2);
3860 rc = RegCreateKeyW(hkey,szComponents,&hkey2);
3861 if (rc != ERROR_SUCCESS)
3862 goto end;
3864 for (i = 0; i < package->loaded_components; i++)
3866 if (package->components[i].ComponentId[0]!=0)
3868 WCHAR *keypath = NULL;
3869 MSIRECORD * uirow;
3871 squash_guid(package->components[i].ComponentId,squished_cc);
3872 rc = RegCreateKeyW(hkey2,squished_cc,&hkey3);
3873 if (rc != ERROR_SUCCESS)
3874 continue;
3876 keypath = resolve_keypath(package,i);
3877 if (keypath)
3879 RegSetValueExW(hkey3,squished_pc,0,REG_SZ,(LPVOID)keypath,
3880 (strlenW(keypath)+1)*sizeof(WCHAR));
3881 RegCloseKey(hkey3);
3883 /* UI stuff */
3884 uirow = MSI_CreateRecord(3);
3885 MSI_RecordSetStringW(uirow,1,productcode);
3886 MSI_RecordSetStringW(uirow,2,package->components[i].
3887 ComponentId);
3888 MSI_RecordSetStringW(uirow,3,keypath);
3889 ui_actiondata(package,szProcessComponents,uirow);
3890 msiobj_release( &uirow->hdr );
3891 HeapFree(GetProcessHeap(),0,keypath);
3895 end:
3896 HeapFree(GetProcessHeap(), 0, productcode);
3897 RegCloseKey(hkey2);
3898 RegCloseKey(hkey);
3899 return rc;
3902 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3905 * OK this is a bit confusing.. I am given a _Component key and I believe
3906 * that the file that is being registered as a type library is the "key file
3907 * of that component" which I interpret to mean "The file in the KeyPath of
3908 * that component".
3910 UINT rc;
3911 MSIQUERY * view;
3912 MSIRECORD * row = 0;
3913 static const WCHAR Query[] = {
3914 'S','E','L','E','C','T',' ','*',' ',
3915 'f','r','o','m',' ','T','y','p','e','L','i','b',0};
3916 ITypeLib *ptLib;
3917 HRESULT res;
3919 if (!package)
3920 return ERROR_INVALID_HANDLE;
3922 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3923 if (rc != ERROR_SUCCESS)
3924 return ERROR_SUCCESS;
3926 rc = MSI_ViewExecute(view, 0);
3927 if (rc != ERROR_SUCCESS)
3929 MSI_ViewClose(view);
3930 msiobj_release(&view->hdr);
3931 return rc;
3934 while (1)
3936 WCHAR component[0x100];
3937 DWORD sz;
3938 INT index;
3940 rc = MSI_ViewFetch(view,&row);
3941 if (rc != ERROR_SUCCESS)
3943 rc = ERROR_SUCCESS;
3944 break;
3947 sz = 0x100;
3948 MSI_RecordGetStringW(row,3,component,&sz);
3950 index = get_loaded_component(package,component);
3951 if (index < 0)
3953 msiobj_release(&row->hdr);
3954 continue;
3957 if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
3959 TRACE("Skipping typelib reg due to disabled component\n");
3960 msiobj_release(&row->hdr);
3961 continue;
3964 index = get_loaded_file(package,package->components[index].KeyPath);
3966 if (index < 0)
3968 msiobj_release(&row->hdr);
3969 continue;
3972 res = LoadTypeLib(package->files[index].TargetPath,&ptLib);
3973 if (SUCCEEDED(res))
3975 LPWSTR help;
3976 WCHAR helpid[0x100];
3978 sz = 0x100;
3979 MSI_RecordGetStringW(row,6,helpid,&sz);
3981 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
3982 res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help);
3983 HeapFree(GetProcessHeap(),0,help);
3985 if (!SUCCEEDED(res))
3986 ERR("Failed to register type library %s\n",
3987 debugstr_w(package->files[index].TargetPath));
3988 else
3990 /* Yes the row has more fields than I need, but #1 is
3991 correct and the only one I need. Why make a new row? */
3993 ui_actiondata(package,szRegisterTypeLibraries,row);
3995 TRACE("Registered %s\n",
3996 debugstr_w(package->files[index].TargetPath));
3999 if (ptLib)
4000 ITypeLib_Release(ptLib);
4002 else
4003 ERR("Failed to load type library %s\n",
4004 debugstr_w(package->files[index].TargetPath));
4006 msiobj_release(&row->hdr);
4008 MSI_ViewClose(view);
4009 msiobj_release(&view->hdr);
4010 return rc;
4014 static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
4016 static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
4017 UINT rc;
4018 MSIQUERY * view;
4019 MSIRECORD * row = 0;
4020 static const WCHAR ExecSeqQuery[] =
4021 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'
4022 ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};
4023 HKEY hkey2,hkey3;
4024 LPWSTR buffer=0;
4026 if (!package)
4027 return ERROR_INVALID_HANDLE;
4029 rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, clsid);
4030 if (rc != ERROR_SUCCESS)
4031 return rc;
4033 rc = MSI_ViewExecute(view, 0);
4034 if (rc != ERROR_SUCCESS)
4036 MSI_ViewClose(view);
4037 msiobj_release(&view->hdr);
4038 return rc;
4041 RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
4042 RegCreateKeyW(hkey2,clsid,&hkey3);
4043 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
4044 (strlenW(app)+1)*sizeof(WCHAR));
4046 rc = MSI_ViewFetch(view,&row);
4047 if (rc != ERROR_SUCCESS)
4049 MSI_ViewClose(view);
4050 msiobj_release(&view->hdr);
4051 return rc;
4054 if (!MSI_RecordIsNull(row,2))
4056 LPWSTR deformated=0;
4057 UINT size;
4058 static const WCHAR szRemoteServerName[] =
4059 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
4060 buffer = load_dynamic_stringW(row,2);
4061 size = deformat_string(package,buffer,&deformated);
4062 RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated,
4063 size);
4064 HeapFree(GetProcessHeap(),0,deformated);
4065 HeapFree(GetProcessHeap(),0,buffer);
4068 if (!MSI_RecordIsNull(row,3))
4070 static const WCHAR szLocalService[] =
4071 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
4072 UINT size;
4073 buffer = load_dynamic_stringW(row,3);
4074 size = (strlenW(buffer)+1) * sizeof(WCHAR);
4075 RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size);
4076 HeapFree(GetProcessHeap(),0,buffer);
4079 if (!MSI_RecordIsNull(row,4))
4081 static const WCHAR szService[] =
4082 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
4083 UINT size;
4084 buffer = load_dynamic_stringW(row,4);
4085 size = (strlenW(buffer)+1) * sizeof(WCHAR);
4086 RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size);
4087 HeapFree(GetProcessHeap(),0,buffer);
4090 if (!MSI_RecordIsNull(row,5))
4092 static const WCHAR szDLL[] =
4093 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
4094 UINT size;
4095 buffer = load_dynamic_stringW(row,5);
4096 size = (strlenW(buffer)+1) * sizeof(WCHAR);
4097 RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size);
4098 HeapFree(GetProcessHeap(),0,buffer);
4101 if (!MSI_RecordIsNull(row,6))
4103 static const WCHAR szActivate[] =
4104 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
4105 static const WCHAR szY[] = {'Y',0};
4107 if (MSI_RecordGetInteger(row,6))
4108 RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
4111 if (!MSI_RecordIsNull(row,7))
4113 static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
4114 static const WCHAR szUser[] =
4115 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
4117 if (MSI_RecordGetInteger(row,7))
4118 RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34);
4121 msiobj_release(&row->hdr);
4122 MSI_ViewClose(view);
4123 msiobj_release(&view->hdr);
4124 RegCloseKey(hkey3);
4125 RegCloseKey(hkey2);
4126 return rc;
4129 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
4132 * Again I am assuming the words, "Whose key file represents" when referring
4133 * to a Component as to meaning that Components KeyPath file
4135 * Also there is a very strong connection between ClassInfo and ProgID
4136 * that I am mostly glossing over.
4137 * What would be more propper is to load the ClassInfo and the ProgID info
4138 * into memory data structures and then be able to enable and disable them
4139 * based on component.
4142 UINT rc;
4143 MSIQUERY * view;
4144 MSIRECORD * row = 0;
4145 static const WCHAR ExecSeqQuery[] = {
4146 'S','E','L','E','C','T',' ','*',' ',
4147 'f','r','o','m',' ','C','l','a','s','s',0};
4148 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
4149 static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
4150 static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
4151 HKEY hkey,hkey2,hkey3;
4153 if (!package)
4154 return ERROR_INVALID_HANDLE;
4156 rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
4157 if (rc != ERROR_SUCCESS)
4158 return ERROR_FUNCTION_FAILED;
4160 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4161 if (rc != ERROR_SUCCESS)
4163 rc = ERROR_SUCCESS;
4164 goto end;
4167 rc = MSI_ViewExecute(view, 0);
4168 if (rc != ERROR_SUCCESS)
4170 MSI_ViewClose(view);
4171 msiobj_release(&view->hdr);
4172 goto end;
4175 while (1)
4177 WCHAR clsid[0x100];
4178 WCHAR buffer[0x100];
4179 WCHAR desc[0x100];
4180 DWORD sz;
4181 INT index;
4183 rc = MSI_ViewFetch(view,&row);
4184 if (rc != ERROR_SUCCESS)
4186 rc = ERROR_SUCCESS;
4187 break;
4190 sz=0x100;
4191 MSI_RecordGetStringW(row,3,buffer,&sz);
4193 index = get_loaded_component(package,buffer);
4195 if (index < 0)
4197 msiobj_release(&row->hdr);
4198 continue;
4201 if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
4203 TRACE("Skipping class reg due to disabled component\n");
4204 msiobj_release(&row->hdr);
4205 continue;
4208 sz=0x100;
4209 MSI_RecordGetStringW(row,1,clsid,&sz);
4210 RegCreateKeyW(hkey,clsid,&hkey2);
4212 if (!MSI_RecordIsNull(row,5))
4214 sz=0x100;
4215 MSI_RecordGetStringW(row,5,desc,&sz);
4217 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc,
4218 (strlenW(desc)+1)*sizeof(WCHAR));
4220 else
4221 desc[0]=0;
4223 sz=0x100;
4224 MSI_RecordGetStringW(row,2,buffer,&sz);
4226 RegCreateKeyW(hkey2,buffer,&hkey3);
4228 index = get_loaded_file(package,package->components[index].KeyPath);
4229 RegSetValueExW(hkey3,NULL,0,REG_SZ,
4230 (LPVOID)package->files[index].TargetPath,
4231 (strlenW(package->files[index].TargetPath)+1)
4232 *sizeof(WCHAR));
4234 RegCloseKey(hkey3);
4236 if (!MSI_RecordIsNull(row,4))
4238 sz=0x100;
4239 MSI_RecordGetStringW(row,4,buffer,&sz);
4241 RegCreateKeyW(hkey2,szProgID,&hkey3);
4243 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer,
4244 (strlenW(buffer)+1)*sizeof(WCHAR));
4246 RegCloseKey(hkey3);
4249 if (!MSI_RecordIsNull(row,6))
4251 sz=0x100;
4252 MSI_RecordGetStringW(row,6,buffer,&sz);
4254 RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer,
4255 (strlenW(buffer)+1)*sizeof(WCHAR));
4257 register_appid(package,buffer,desc);
4260 RegCloseKey(hkey2);
4262 FIXME("Process the rest of the fields >7\n");
4264 ui_actiondata(package,szRegisterClassInfo,row);
4266 msiobj_release(&row->hdr);
4268 MSI_ViewClose(view);
4269 msiobj_release(&view->hdr);
4271 end:
4272 RegCloseKey(hkey);
4273 return rc;
4276 static UINT register_progid_base(MSIRECORD * row, LPWSTR clsid)
4278 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
4279 HKEY hkey,hkey2;
4280 WCHAR buffer[0x100];
4281 DWORD sz;
4284 sz = 0x100;
4285 MSI_RecordGetStringW(row,1,buffer,&sz);
4286 RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
4288 if (!MSI_RecordIsNull(row,4))
4290 sz = 0x100;
4291 MSI_RecordGetStringW(row,4,buffer,&sz);
4292 RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
4293 sizeof(WCHAR));
4296 if (!MSI_RecordIsNull(row,3))
4298 sz = 0x100;
4300 MSI_RecordGetStringW(row,3,buffer,&sz);
4301 RegCreateKeyW(hkey,szCLSID,&hkey2);
4302 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
4303 sizeof(WCHAR));
4305 if (clsid)
4306 strcpyW(clsid,buffer);
4308 RegCloseKey(hkey2);
4310 else
4312 FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
4313 return ERROR_FUNCTION_FAILED;
4315 if (!MSI_RecordIsNull(row,5))
4316 FIXME ("UNHANDLED icon in Progid\n");
4317 return ERROR_SUCCESS;
4320 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid);
4322 static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent,
4323 LPWSTR clsid)
4325 UINT rc;
4326 MSIQUERY * view;
4327 MSIRECORD * row = 0;
4328 static const WCHAR Query_t[] =
4329 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'
4330 ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'
4331 ,'%','s','`',0};
4333 if (!package)
4334 return ERROR_INVALID_HANDLE;
4336 rc = ACTION_OpenQuery(package->db, &view, Query_t, parent);
4337 if (rc != ERROR_SUCCESS)
4338 return rc;
4340 rc = MSI_ViewExecute(view, 0);
4341 if (rc != ERROR_SUCCESS)
4343 MSI_ViewClose(view);
4344 msiobj_release(&view->hdr);
4345 return rc;
4348 rc = MSI_ViewFetch(view,&row);
4349 if (rc != ERROR_SUCCESS)
4351 MSI_ViewClose(view);
4352 msiobj_release(&view->hdr);
4353 return rc;
4356 register_progid(package,row,clsid);
4358 msiobj_release(&row->hdr);
4359 MSI_ViewClose(view);
4360 msiobj_release(&view->hdr);
4361 return rc;
4364 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid)
4366 UINT rc = ERROR_SUCCESS;
4368 if (MSI_RecordIsNull(row,2))
4369 rc = register_progid_base(row,clsid);
4370 else
4372 WCHAR buffer[0x1000];
4373 DWORD sz, disp;
4374 HKEY hkey,hkey2;
4375 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
4377 /* check if already registered */
4378 sz = 0x100;
4379 MSI_RecordGetStringW(row,1,buffer,&sz);
4380 RegCreateKeyExW(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0,
4381 KEY_ALL_ACCESS, NULL, &hkey, &disp );
4382 if (disp == REG_OPENED_EXISTING_KEY)
4384 TRACE("Key already registered\n");
4385 RegCloseKey(hkey);
4386 return rc;
4388 /* clsid is same as parent */
4389 RegCreateKeyW(hkey,szCLSID,&hkey2);
4390 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
4391 sizeof(WCHAR));
4393 RegCloseKey(hkey2);
4395 sz = 0x100;
4396 MSI_RecordGetStringW(row,2,buffer,&sz);
4397 rc = register_parent_progid(package,buffer,clsid);
4399 if (!MSI_RecordIsNull(row,4))
4401 sz = 0x100;
4402 MSI_RecordGetStringW(row,4,buffer,&sz);
4403 RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer,
4404 (strlenW(buffer)+1) * sizeof(WCHAR));
4407 if (!MSI_RecordIsNull(row,5))
4408 FIXME ("UNHANDLED icon in Progid\n");
4410 RegCloseKey(hkey);
4412 return rc;
4415 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
4418 * Sigh, here I am just brute force registering all progids
4419 * this needs to be linked to the Classes that have been registered
4420 * but the easiest way to do that is to load all these stuff into
4421 * memory for easy checking.
4423 * Gives me something to continue to work toward.
4425 UINT rc;
4426 MSIQUERY * view;
4427 MSIRECORD * row = 0;
4428 static const WCHAR Query[] = {
4429 'S','E','L','E','C','T',' ','*',' ',
4430 'F','R','O','M',' ','P','r','o','g','I','d',0};
4432 if (!package)
4433 return ERROR_INVALID_HANDLE;
4435 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4436 if (rc != ERROR_SUCCESS)
4437 return ERROR_SUCCESS;
4439 rc = MSI_ViewExecute(view, 0);
4440 if (rc != ERROR_SUCCESS)
4442 MSI_ViewClose(view);
4443 msiobj_release(&view->hdr);
4444 return rc;
4447 while (1)
4449 WCHAR clsid[0x1000];
4451 rc = MSI_ViewFetch(view,&row);
4452 if (rc != ERROR_SUCCESS)
4454 rc = ERROR_SUCCESS;
4455 break;
4458 register_progid(package,row,clsid);
4459 ui_actiondata(package,szRegisterProgIdInfo,row);
4461 msiobj_release(&row->hdr);
4463 MSI_ViewClose(view);
4464 msiobj_release(&view->hdr);
4465 return rc;
4468 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name,
4469 LPWSTR *FilePath)
4471 LPWSTR ProductCode;
4472 LPWSTR SystemFolder;
4473 LPWSTR dest;
4474 UINT rc;
4476 static const WCHAR szInstaller[] =
4477 {'I','n','s','t','a','l','l','e','r','\\',0};
4478 static const WCHAR szProductCode[] =
4479 {'P','r','o','d','u','c','t','C','o','d','e',0};
4480 static const WCHAR szFolder[] =
4481 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
4483 ProductCode = load_dynamic_property(package,szProductCode,&rc);
4484 if (!ProductCode)
4485 return rc;
4487 SystemFolder = load_dynamic_property(package,szFolder,NULL);
4489 dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);
4491 create_full_pathW(dest);
4493 *FilePath = build_directory_name(2, dest, icon_name);
4495 HeapFree(GetProcessHeap(),0,SystemFolder);
4496 HeapFree(GetProcessHeap(),0,ProductCode);
4497 HeapFree(GetProcessHeap(),0,dest);
4498 return ERROR_SUCCESS;
4501 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
4503 UINT rc;
4504 MSIQUERY * view;
4505 MSIRECORD * row = 0;
4506 static const WCHAR Query[] = {
4507 'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ',
4508 'S','h','o','r','t','c','u','t',0};
4509 IShellLinkW *sl;
4510 IPersistFile *pf;
4511 HRESULT res;
4513 if (!package)
4514 return ERROR_INVALID_HANDLE;
4516 res = CoInitialize( NULL );
4517 if (FAILED (res))
4519 ERR("CoInitialize failed\n");
4520 return ERROR_FUNCTION_FAILED;
4523 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4524 if (rc != ERROR_SUCCESS)
4525 return ERROR_SUCCESS;
4527 rc = MSI_ViewExecute(view, 0);
4528 if (rc != ERROR_SUCCESS)
4530 MSI_ViewClose(view);
4531 msiobj_release(&view->hdr);
4532 return rc;
4535 while (1)
4537 LPWSTR target_file, target_folder;
4538 WCHAR buffer[0x100];
4539 DWORD sz;
4540 DWORD index;
4541 static const WCHAR szlnk[]={'.','l','n','k',0};
4543 rc = MSI_ViewFetch(view,&row);
4544 if (rc != ERROR_SUCCESS)
4546 rc = ERROR_SUCCESS;
4547 break;
4550 sz = 0x100;
4551 MSI_RecordGetStringW(row,4,buffer,&sz);
4553 index = get_loaded_component(package,buffer);
4555 if (index < 0)
4557 msiobj_release(&row->hdr);
4558 continue;
4561 if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
4563 TRACE("Skipping shortcut creation due to disabled component\n");
4564 msiobj_release(&row->hdr);
4565 continue;
4568 ui_actiondata(package,szCreateShortcuts,row);
4570 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
4571 &IID_IShellLinkW, (LPVOID *) &sl );
4573 if (FAILED(res))
4575 ERR("Is IID_IShellLink\n");
4576 msiobj_release(&row->hdr);
4577 continue;
4580 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
4581 if( FAILED( res ) )
4583 ERR("Is IID_IPersistFile\n");
4584 msiobj_release(&row->hdr);
4585 continue;
4588 sz = 0x100;
4589 MSI_RecordGetStringW(row,2,buffer,&sz);
4590 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
4592 /* may be needed because of a bug somehwere else */
4593 create_full_pathW(target_folder);
4595 sz = 0x100;
4596 MSI_RecordGetStringW(row,3,buffer,&sz);
4597 reduce_to_longfilename(buffer);
4598 if (!strchrW(buffer,'.'))
4599 strcatW(buffer,szlnk);
4600 target_file = build_directory_name(2, target_folder, buffer);
4601 HeapFree(GetProcessHeap(),0,target_folder);
4603 sz = 0x100;
4604 MSI_RecordGetStringW(row,5,buffer,&sz);
4605 if (strchrW(buffer,'['))
4607 LPWSTR deformated;
4608 deformat_string(package,buffer,&deformated);
4609 IShellLinkW_SetPath(sl,deformated);
4610 HeapFree(GetProcessHeap(),0,deformated);
4612 else
4614 FIXME("UNHANDLED shortcut format, advertised shortcut\n");
4615 IPersistFile_Release( pf );
4616 IShellLinkW_Release( sl );
4617 msiobj_release(&row->hdr);
4618 continue;
4621 if (!MSI_RecordIsNull(row,6))
4623 LPWSTR deformated;
4624 sz = 0x100;
4625 MSI_RecordGetStringW(row,6,buffer,&sz);
4626 deformat_string(package,buffer,&deformated);
4627 IShellLinkW_SetArguments(sl,deformated);
4628 HeapFree(GetProcessHeap(),0,deformated);
4631 if (!MSI_RecordIsNull(row,7))
4633 LPWSTR deformated;
4634 deformated = load_dynamic_stringW(row,7);
4635 IShellLinkW_SetDescription(sl,deformated);
4636 HeapFree(GetProcessHeap(),0,deformated);
4639 if (!MSI_RecordIsNull(row,8))
4640 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
4642 if (!MSI_RecordIsNull(row,9))
4644 WCHAR *Path = NULL;
4645 INT index;
4647 sz = 0x100;
4648 MSI_RecordGetStringW(row,9,buffer,&sz);
4650 build_icon_path(package,buffer,&Path);
4651 index = MSI_RecordGetInteger(row,10);
4653 IShellLinkW_SetIconLocation(sl,Path,index);
4654 HeapFree(GetProcessHeap(),0,Path);
4657 if (!MSI_RecordIsNull(row,11))
4658 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
4660 if (!MSI_RecordIsNull(row,12))
4662 LPWSTR Path;
4663 sz = 0x100;
4664 MSI_RecordGetStringW(row,12,buffer,&sz);
4665 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
4666 IShellLinkW_SetWorkingDirectory(sl,Path);
4667 HeapFree(GetProcessHeap(), 0, Path);
4670 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
4671 IPersistFile_Save(pf,target_file,FALSE);
4673 HeapFree(GetProcessHeap(),0,target_file);
4675 IPersistFile_Release( pf );
4676 IShellLinkW_Release( sl );
4678 msiobj_release(&row->hdr);
4680 MSI_ViewClose(view);
4681 msiobj_release(&view->hdr);
4684 CoUninitialize();
4686 return rc;
4691 * 99% of the work done here is only done for
4692 * advertised installs. However this is where the
4693 * Icon table is processed and written out
4694 * so that is what I am going to do here.
4696 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4698 UINT rc;
4699 MSIQUERY * view;
4700 MSIRECORD * row = 0;
4701 static const WCHAR Query[]={
4702 'S','E','L','E','C','T',' ','*',' ',
4703 'f','r','o','m',' ','I','c','o','n',0};
4704 DWORD sz;
4706 if (!package)
4707 return ERROR_INVALID_HANDLE;
4709 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4710 if (rc != ERROR_SUCCESS)
4711 return ERROR_SUCCESS;
4713 rc = MSI_ViewExecute(view, 0);
4714 if (rc != ERROR_SUCCESS)
4716 MSI_ViewClose(view);
4717 msiobj_release(&view->hdr);
4718 return rc;
4721 while (1)
4723 HANDLE the_file;
4724 WCHAR *FilePath=NULL;
4725 WCHAR *FileName=NULL;
4726 CHAR buffer[1024];
4728 rc = MSI_ViewFetch(view,&row);
4729 if (rc != ERROR_SUCCESS)
4731 rc = ERROR_SUCCESS;
4732 break;
4735 FileName = load_dynamic_stringW(row,1);
4736 if (!FileName)
4738 ERR("Unable to get FileName\n");
4739 msiobj_release(&row->hdr);
4740 continue;
4743 build_icon_path(package,FileName,&FilePath);
4745 HeapFree(GetProcessHeap(),0,FileName);
4747 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
4749 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
4750 FILE_ATTRIBUTE_NORMAL, NULL);
4752 if (the_file == INVALID_HANDLE_VALUE)
4754 ERR("Unable to create file %s\n",debugstr_w(FilePath));
4755 msiobj_release(&row->hdr);
4756 HeapFree(GetProcessHeap(),0,FilePath);
4757 continue;
4762 DWORD write;
4763 sz = 1024;
4764 rc = MSI_RecordReadStream(row,2,buffer,&sz);
4765 if (rc != ERROR_SUCCESS)
4767 ERR("Failed to get stream\n");
4768 CloseHandle(the_file);
4769 DeleteFileW(FilePath);
4770 break;
4772 WriteFile(the_file,buffer,sz,&write,NULL);
4773 } while (sz == 1024);
4775 HeapFree(GetProcessHeap(),0,FilePath);
4777 CloseHandle(the_file);
4778 msiobj_release(&row->hdr);
4780 MSI_ViewClose(view);
4781 msiobj_release(&view->hdr);
4782 return rc;
4786 /* Msi functions that seem appropriate here */
4787 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
4789 LPWSTR szwAction;
4790 UINT rc;
4792 TRACE(" exteral attempt at action %s\n",szAction);
4794 if (!szAction)
4795 return ERROR_FUNCTION_FAILED;
4796 if (hInstall == 0)
4797 return ERROR_FUNCTION_FAILED;
4799 szwAction = strdupAtoW(szAction);
4801 if (!szwAction)
4802 return ERROR_FUNCTION_FAILED;
4805 rc = MsiDoActionW(hInstall, szwAction);
4806 HeapFree(GetProcessHeap(),0,szwAction);
4807 return rc;
4810 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
4812 MSIPACKAGE *package;
4813 UINT ret = ERROR_INVALID_HANDLE;
4815 TRACE(" external attempt at action %s \n",debugstr_w(szAction));
4817 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4818 if( package )
4820 ret = ACTION_PerformAction(package,szAction);
4821 msiobj_release( &package->hdr );
4823 return ret;
4826 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
4827 LPSTR szPathBuf, DWORD* pcchPathBuf)
4829 LPWSTR szwFolder;
4830 LPWSTR szwPathBuf;
4831 UINT rc;
4833 TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
4835 if (!szFolder)
4836 return ERROR_FUNCTION_FAILED;
4837 if (hInstall == 0)
4838 return ERROR_FUNCTION_FAILED;
4840 szwFolder = strdupAtoW(szFolder);
4842 if (!szwFolder)
4843 return ERROR_FUNCTION_FAILED;
4845 szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
4847 rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
4849 WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
4850 *pcchPathBuf, NULL, NULL );
4852 HeapFree(GetProcessHeap(),0,szwFolder);
4853 HeapFree(GetProcessHeap(),0,szwPathBuf);
4855 return rc;
4858 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
4859 szPathBuf, DWORD* pcchPathBuf)
4861 LPWSTR path;
4862 UINT rc = ERROR_FUNCTION_FAILED;
4863 MSIPACKAGE *package;
4865 TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
4867 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4868 if (!package)
4869 return ERROR_INVALID_HANDLE;
4870 path = resolve_folder(package, szFolder, FALSE, FALSE, NULL);
4871 msiobj_release( &package->hdr );
4873 if (path && (strlenW(path) > *pcchPathBuf))
4875 *pcchPathBuf = strlenW(path)+1;
4876 rc = ERROR_MORE_DATA;
4878 else if (path)
4880 *pcchPathBuf = strlenW(path)+1;
4881 strcpyW(szPathBuf,path);
4882 TRACE("Returning Path %s\n",debugstr_w(path));
4883 rc = ERROR_SUCCESS;
4885 HeapFree(GetProcessHeap(),0,path);
4887 return rc;
4891 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder,
4892 LPSTR szPathBuf, DWORD* pcchPathBuf)
4894 LPWSTR szwFolder;
4895 LPWSTR szwPathBuf;
4896 UINT rc;
4898 TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
4900 if (!szFolder)
4901 return ERROR_FUNCTION_FAILED;
4902 if (hInstall == 0)
4903 return ERROR_FUNCTION_FAILED;
4905 szwFolder = strdupAtoW(szFolder);
4906 if (!szwFolder)
4907 return ERROR_FUNCTION_FAILED;
4909 szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
4911 rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
4913 WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
4914 *pcchPathBuf, NULL, NULL );
4916 HeapFree(GetProcessHeap(),0,szwFolder);
4917 HeapFree(GetProcessHeap(),0,szwPathBuf);
4919 return rc;
4922 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
4923 szPathBuf, DWORD* pcchPathBuf)
4925 LPWSTR path;
4926 UINT rc = ERROR_FUNCTION_FAILED;
4927 MSIPACKAGE *package;
4929 TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
4931 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4932 if( !package )
4933 return ERROR_INVALID_HANDLE;
4934 path = resolve_folder(package, szFolder, TRUE, FALSE, NULL);
4935 msiobj_release( &package->hdr );
4937 if (path && strlenW(path) > *pcchPathBuf)
4939 *pcchPathBuf = strlenW(path)+1;
4940 rc = ERROR_MORE_DATA;
4942 else if (path)
4944 *pcchPathBuf = strlenW(path)+1;
4945 strcpyW(szPathBuf,path);
4946 TRACE("Returning Path %s\n",debugstr_w(path));
4947 rc = ERROR_SUCCESS;
4949 HeapFree(GetProcessHeap(),0,path);
4951 return rc;
4955 UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder,
4956 LPCSTR szFolderPath)
4958 LPWSTR szwFolder;
4959 LPWSTR szwFolderPath;
4960 UINT rc;
4962 if (!szFolder)
4963 return ERROR_FUNCTION_FAILED;
4964 if (hInstall == 0)
4965 return ERROR_FUNCTION_FAILED;
4967 szwFolder = strdupAtoW(szFolder);
4968 if (!szwFolder)
4969 return ERROR_FUNCTION_FAILED;
4971 szwFolderPath = strdupAtoW(szFolderPath);
4972 if (!szwFolderPath)
4974 HeapFree(GetProcessHeap(),0,szwFolder);
4975 return ERROR_FUNCTION_FAILED;
4978 rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
4980 HeapFree(GetProcessHeap(),0,szwFolder);
4981 HeapFree(GetProcessHeap(),0,szwFolderPath);
4983 return rc;
4986 UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
4987 LPCWSTR szFolderPath)
4989 DWORD i;
4990 LPWSTR path = NULL;
4991 MSIFOLDER *folder;
4993 TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
4995 if (package==NULL)
4996 return ERROR_INVALID_HANDLE;
4998 if (szFolderPath[0]==0)
4999 return ERROR_FUNCTION_FAILED;
5001 if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)
5002 return ERROR_FUNCTION_FAILED;
5004 path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);
5005 if (!path)
5006 return ERROR_INVALID_PARAMETER;
5007 HeapFree(GetProcessHeap(),0,path);
5009 strcpyW(folder->Property,szFolderPath);
5011 for (i = 0; i < package->loaded_folders; i++)
5012 package->folders[i].ResolvedTarget=NULL;
5014 for (i = 0; i < package->loaded_folders; i++)
5016 path = resolve_folder(package, package->folders[i].Directory, FALSE,
5017 TRUE, NULL);
5018 HeapFree(GetProcessHeap(),0,path);
5021 return ERROR_SUCCESS;
5024 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
5025 LPCWSTR szFolderPath)
5027 MSIPACKAGE *package;
5028 UINT ret;
5030 TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
5032 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5033 ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
5034 msiobj_release( &package->hdr );
5035 return ret;
5038 /***********************************************************************
5039 * MsiGetMode (MSI.@)
5041 * Returns an internal installer state (if it is running in a mode iRunMode)
5043 * PARAMS
5044 * hInstall [I] Handle to the installation
5045 * hRunMode [I] Checking run mode
5046 * MSIRUNMODE_ADMIN Administrative mode
5047 * MSIRUNMODE_ADVERTISE Advertisement mode
5048 * MSIRUNMODE_MAINTENANCE Maintenance mode
5049 * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled
5050 * MSIRUNMODE_LOGENABLED Log file is writing
5051 * MSIRUNMODE_OPERATIONS Operations in progress??
5052 * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed
5053 * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation
5054 * MSIRUNMODE_CABINET Files from cabinet are installed
5055 * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is supressed
5056 * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is supressed
5057 * MSIRUNMODE_RESERVED11 Reserved
5058 * MSIRUNMODE_WINDOWS9X Running under Windows95/98
5059 * MSIRUNMODE_ZAWENABLED Demand installation is supported
5060 * MSIRUNMODE_RESERVED14 Reserved
5061 * MSIRUNMODE_RESERVED15 Reserved
5062 * MSIRUNMODE_SCHEDULED called from install script
5063 * MSIRUNMODE_ROLLBACK called from rollback script
5064 * MSIRUNMODE_COMMIT called from commit script
5066 * RETURNS
5067 * In the state: TRUE
5068 * Not in the state: FALSE
5072 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
5074 FIXME("STUB (iRunMode=%i)\n",iRunMode);
5075 return TRUE;
5079 * According to the docs, when this is called it immediately recalculates
5080 * all the component states as well
5082 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
5083 INSTALLSTATE iState)
5085 LPWSTR szwFeature = NULL;
5086 UINT rc;
5088 szwFeature = strdupAtoW(szFeature);
5090 if (!szwFeature)
5091 return ERROR_FUNCTION_FAILED;
5093 rc = MsiSetFeatureStateW(hInstall,szwFeature, iState);
5095 HeapFree(GetProcessHeap(),0,szwFeature);
5097 return rc;
5100 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
5101 INSTALLSTATE iState)
5103 MSIPACKAGE* package;
5104 INT index;
5106 TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
5108 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5109 if (!package)
5110 return ERROR_INVALID_HANDLE;
5112 index = get_loaded_feature(package,szFeature);
5113 if (index < 0)
5114 return ERROR_UNKNOWN_FEATURE;
5116 package->features[index].ActionRequest= iState;
5118 return ERROR_SUCCESS;
5121 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
5122 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5124 LPWSTR szwFeature = NULL;
5125 UINT rc;
5127 szwFeature = strdupAtoW(szFeature);
5129 rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
5131 HeapFree( GetProcessHeap(), 0 , szwFeature);
5133 return rc;
5136 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
5137 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5139 INT index;
5141 index = get_loaded_feature(package,szFeature);
5142 if (index < 0)
5143 return ERROR_UNKNOWN_FEATURE;
5145 if (piInstalled)
5146 *piInstalled = package->features[index].Installed;
5148 if (piAction)
5149 *piAction = package->features[index].Action;
5151 TRACE("returning %i %i\n",*piInstalled,*piAction);
5153 return ERROR_SUCCESS;
5156 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
5157 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5159 MSIPACKAGE* package;
5160 UINT ret;
5162 TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
5163 piAction);
5165 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5166 if (!package)
5167 return ERROR_INVALID_HANDLE;
5168 ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
5169 msiobj_release( &package->hdr );
5170 return ret;
5173 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
5174 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5176 LPWSTR szwComponent= NULL;
5177 UINT rc;
5179 szwComponent= strdupAtoW(szComponent);
5181 rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
5183 HeapFree( GetProcessHeap(), 0 , szwComponent);
5185 return rc;
5188 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
5189 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5191 INT index;
5193 TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
5194 piAction);
5196 index = get_loaded_component(package,szComponent);
5197 if (index < 0)
5198 return ERROR_UNKNOWN_COMPONENT;
5200 if (piInstalled)
5201 *piInstalled = package->components[index].Installed;
5203 if (piAction)
5204 *piInstalled = package->components[index].Action;
5206 return ERROR_SUCCESS;
5209 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
5210 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
5212 MSIPACKAGE* package;
5213 UINT ret;
5215 TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
5216 piInstalled, piAction);
5218 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
5219 if (!package)
5220 return ERROR_INVALID_HANDLE;
5221 ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
5222 msiobj_release( &package->hdr );
5223 return ret;
5226 #if 0
5227 static UINT ACTION_Template(MSIPACKAGE *package)
5229 UINT rc;
5230 MSIQUERY * view;
5231 MSIRECORD * row = 0;
5232 static const WCHAR ExecSeqQuery[] = {0};
5234 rc = MsiDatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5235 if (rc != ERROR_SUCCESS)
5236 return rc;
5238 rc = MsiViewExecute(view, 0);
5239 if (rc != ERROR_SUCCESS)
5241 MsiViewClose(view);
5242 msiobj_release(&view->hdr);
5243 return rc;
5246 while (1)
5248 rc = MsiViewFetch(view,&row);
5249 if (rc != ERROR_SUCCESS)
5251 rc = ERROR_SUCCESS;
5252 break;
5255 msiobj_release(&row->hdr);
5257 MsiViewClose(view);
5258 msiobj_release(&view->hdr);
5259 return rc;
5261 #endif