Implemented registering Classes and ProgID.
[wine/gsoc_dplay.git] / dlls / msi / action.c
blob86f41ce9161f7370efdfca9496b5241212a5e60e
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 #include "windef.h"
33 #include "winbase.h"
34 #include "winerror.h"
35 #include "winreg.h"
36 #include "wine/debug.h"
37 #include "msi.h"
38 #include "msiquery.h"
39 #include "objbase.h"
40 #include "objidl.h"
41 #include "msipriv.h"
42 #include "winnls.h"
43 #include "winuser.h"
44 #include "shlobj.h"
45 #include "wine/unicode.h"
46 #include "ver.h"
48 #define CUSTOM_ACTION_TYPE_MASK 0x3F
50 WINE_DEFAULT_DEBUG_CHANNEL(msi);
52 typedef struct tagMSIFEATURE
54 WCHAR Feature[96];
55 WCHAR Feature_Parent[96];
56 WCHAR Title[0x100];
57 WCHAR Description[0x100];
58 INT Display;
59 INT Level;
60 WCHAR Directory[96];
61 INT Attributes;
63 INSTALLSTATE State;
64 INT ComponentCount;
65 INT Components[1024]; /* yes hardcoded limit.... I am bad */
66 INT Cost;
67 } MSIFEATURE;
69 typedef struct tagMSICOMPONENT
71 WCHAR Component[96];
72 WCHAR ComponentId[96];
73 WCHAR Directory[96];
74 INT Attributes;
75 WCHAR Condition[0x100];
76 WCHAR KeyPath[96];
78 INSTALLSTATE State;
79 BOOL FeatureState;
80 BOOL Enabled;
81 INT Cost;
82 }MSICOMPONENT;
84 typedef struct tagMSIFOLDER
86 WCHAR Directory[96];
87 WCHAR TargetDefault[96];
88 WCHAR SourceDefault[96];
90 WCHAR ResolvedTarget[MAX_PATH];
91 WCHAR ResolvedSource[MAX_PATH];
92 WCHAR Property[MAX_PATH]; /* initialy set property */
93 INT ParentIndex;
94 INT State;
95 /* 0 = uninitialized */
96 /* 1 = existing */
97 /* 2 = created remove if empty */
98 /* 3 = created persist if empty */
99 INT Cost;
100 INT Space;
101 }MSIFOLDER;
103 typedef struct tagMSIFILE
105 WCHAR File[72];
106 INT ComponentIndex;
107 WCHAR FileName[MAX_PATH];
108 INT FileSize;
109 WCHAR Version[72];
110 WCHAR Language[20];
111 INT Attributes;
112 INT Sequence;
114 INT State;
115 /* 0 = uninitialize */
116 /* 1 = not present */
117 /* 2 = present but replace */
118 /* 3 = present do not replace */
119 /* 4 = Installed */
120 WCHAR SourcePath[MAX_PATH];
121 WCHAR TargetPath[MAX_PATH];
122 BOOL Temporary;
123 }MSIFILE;
126 * Prototypes
128 static UINT ACTION_ProcessExecSequence(MSIHANDLE hPackage, BOOL UIran);
129 static UINT ACTION_ProcessUISequence(MSIHANDLE hPackage);
131 UINT ACTION_PerformAction(MSIHANDLE hPackage, const WCHAR *action);
133 static UINT ACTION_LaunchConditions(MSIHANDLE hPackage);
134 static UINT ACTION_CostInitialize(MSIHANDLE hPackage);
135 static UINT ACTION_CreateFolders(MSIHANDLE hPackage);
136 static UINT ACTION_CostFinalize(MSIHANDLE hPackage);
137 static UINT ACTION_FileCost(MSIHANDLE hPackage);
138 static UINT ACTION_InstallFiles(MSIHANDLE hPackage);
139 static UINT ACTION_DuplicateFiles(MSIHANDLE hPackage);
140 static UINT ACTION_WriteRegistryValues(MSIHANDLE hPackage);
141 static UINT ACTION_CustomAction(MSIHANDLE hPackage,const WCHAR *action);
142 static UINT ACTION_InstallInitialize(MSIHANDLE hPackage);
143 static UINT ACTION_InstallValidate(MSIHANDLE hPackage);
144 static UINT ACTION_ProcessComponents(MSIHANDLE hPackage);
145 static UINT ACTION_RegisterTypeLibraries(MSIHANDLE hPackage);
146 static UINT ACTION_RegisterClassInfo(MSIHANDLE hPackage);
147 static UINT ACTION_RegisterProgIdInfo(MSIHANDLE hPackage);
149 static UINT HANDLE_CustomType1(MSIHANDLE hPackage, const LPWSTR source,
150 const LPWSTR target, const INT type);
151 static UINT HANDLE_CustomType2(MSIHANDLE hPackage, const LPWSTR source,
152 const LPWSTR target, const INT type);
154 static DWORD deformat_string(MSIHANDLE hPackage, WCHAR* ptr,WCHAR** data);
155 static UINT resolve_folder(MSIHANDLE hPackage, LPCWSTR name, LPWSTR path,
156 BOOL source, BOOL set_prop, MSIFOLDER **folder);
158 static UINT track_tempfile(MSIHANDLE hPackage, LPCWSTR name, LPCWSTR path);
161 * consts and values used
163 static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
164 static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
165 static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
166 static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
167 static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
168 static const WCHAR c_collen[] = {'C',':','\\',0};
170 static const WCHAR cszlsb[]={'[',0};
171 static const WCHAR cszrsb[]={']',0};
172 static const WCHAR cszbs[]={'\\',0};
174 const static WCHAR szCreateFolders[] =
175 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
176 const static WCHAR szCostFinalize[] =
177 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
178 const static WCHAR szInstallFiles[] =
179 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
180 const static WCHAR szDuplicateFiles[] =
181 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
182 const static WCHAR szWriteRegistryValues[] =
183 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
184 const static WCHAR szCostInitialize[] =
185 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
186 const static WCHAR szFileCost[] = {'F','i','l','e','C','o','s','t',0};
187 const static WCHAR szInstallInitialize[] =
188 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
189 const static WCHAR szInstallValidate[] =
190 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
191 const static WCHAR szLaunchConditions[] =
192 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
193 const static WCHAR szProcessComponents[] =
194 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
195 const static WCHAR szRegisterTypeLibraries[] =
196 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r',
197 'i','e','s',0};
198 const static WCHAR szRegisterClassInfo[] =
199 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
200 const static WCHAR szRegisterProgIdInfo[] =
201 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
203 /********************************************************
204 * helper functions to get around current HACKS and such
205 ********************************************************/
206 inline static void reduce_to_longfilename(WCHAR* filename)
208 if (strchrW(filename,'|'))
210 WCHAR newname[MAX_PATH];
211 strcpyW(newname,strchrW(filename,'|')+1);
212 strcpyW(filename,newname);
216 inline static char *strdupWtoA( const WCHAR *str )
218 char *ret = NULL;
219 if (str)
221 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL
223 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
224 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
226 return ret;
229 inline static int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
231 INT rc = -1;
232 INT i;
234 for (i = 0; i < package->loaded_components; i++)
236 if (strcmpW(Component,package->components[i].Component)==0)
238 rc = i;
239 break;
242 return rc;
245 inline static int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
247 INT rc = -1;
248 INT i;
250 for (i = 0; i < package->loaded_features; i++)
252 if (strcmpW(Feature,package->features[i].Feature)==0)
254 rc = i;
255 break;
258 return rc;
261 inline static int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
263 INT rc = -1;
264 INT i;
266 for (i = 0; i < package->loaded_files; i++)
268 if (strcmpW(file,package->files[i].File)==0)
270 rc = i;
271 break;
274 return rc;
277 static UINT track_tempfile(MSIHANDLE hPackage, LPCWSTR name, LPCWSTR path)
279 MSIPACKAGE *package;
280 int i;
281 int index;
283 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
285 if (!package)
286 return -2;
288 for (i=0; i < package->loaded_files; i++)
289 if (strcmpW(package->files[i].File,name)==0)
290 return -1;
292 index = package->loaded_files;
293 package->loaded_files++;
294 if (package->loaded_files== 1)
295 package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
296 else
297 package->files = HeapReAlloc(GetProcessHeap(),0,
298 package->files , package->loaded_files * sizeof(MSIFILE));
300 memset(&package->files[index],0,sizeof(MSIFILE));
302 strcpyW(package->files[index].File,name);
303 strcpyW(package->files[index].TargetPath,path);
304 package->files[index].Temporary = TRUE;
306 TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));
308 return 0;
311 void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package)
313 int i;
315 if (!package)
316 return;
318 for (i = 0; i < package->loaded_files; i++)
320 if (package->files[i].Temporary)
321 DeleteFileW(package->files[i].TargetPath);
326 static void ui_progress(MSIHANDLE hPackage, int a, int b, int c, int d )
328 MSIHANDLE row;
330 row = MsiCreateRecord(4);
331 MsiRecordSetInteger(row,1,a);
332 MsiRecordSetInteger(row,2,b);
333 MsiRecordSetInteger(row,3,c);
334 MsiRecordSetInteger(row,4,d);
335 MsiProcessMessage(hPackage, INSTALLMESSAGE_PROGRESS, row);
336 MsiCloseHandle(row);
339 static void ui_actiondata(MSIHANDLE hPackage, LPCWSTR action, MSIHANDLE record)
341 static const WCHAR Query_t[] =
342 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
343 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
344 ' ','\'','%','s','\'',0};
345 WCHAR message[1024];
346 UINT rc;
347 MSIHANDLE view;
348 MSIHANDLE row = 0;
349 WCHAR *ActionFormat=NULL;
350 DWORD sz;
351 WCHAR Query[1024];
352 MSIHANDLE db;
353 LPWSTR ptr;
355 sprintfW(Query,Query_t,action);
356 db = MsiGetActiveDatabase(hPackage);
357 rc = MsiDatabaseOpenViewW(db, Query, &view);
358 MsiCloseHandle(db);
359 MsiViewExecute(view, 0);
360 rc = MsiViewFetch(view,&row);
361 if (rc != ERROR_SUCCESS)
363 MsiViewClose(view);
364 MsiCloseHandle(view);
365 return;
368 if (MsiRecordIsNull(row,3))
370 MsiCloseHandle(row);
371 MsiViewClose(view);
372 MsiCloseHandle(view);
373 return;
375 sz = 0;
376 MsiRecordGetStringW(row,3,NULL,&sz);
377 sz++;
378 ActionFormat = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
379 MsiRecordGetStringW(row,3,ActionFormat,&sz);
380 MsiCloseHandle(row);
381 MsiViewClose(view);
382 MsiCloseHandle(view);
384 message[0]=0;
385 ptr = ActionFormat;
386 while (*ptr)
388 LPWSTR ptr2;
389 LPWSTR data=NULL;
390 WCHAR tmp[1023];
391 INT field;
393 ptr2 = strchrW(ptr,'[');
394 if (ptr2)
396 strncpyW(tmp,ptr,ptr2-ptr);
397 tmp[ptr2-ptr]=0;
398 strcatW(message,tmp);
399 ptr2++;
400 field = atoiW(ptr2);
401 sz = 0;
402 MsiRecordGetStringW(record,field,NULL,&sz);
403 sz++;
404 data = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
405 MsiRecordGetStringW(record,field,data,&sz);
406 strcatW(message,data);
407 HeapFree(GetProcessHeap(),0,data);
408 ptr=strchrW(ptr2,']');
409 ptr++;
411 else
413 strcatW(message,ptr);
414 break;
418 row = MsiCreateRecord(1);
419 MsiRecordSetStringW(row,1,message);
421 MsiProcessMessage(hPackage, INSTALLMESSAGE_ACTIONDATA, row);
422 MsiCloseHandle(row);
423 HeapFree(GetProcessHeap(),0,ActionFormat);
427 static void ui_actionstart(MSIHANDLE hPackage, LPCWSTR action)
429 static const WCHAR template_s[]=
430 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ','%','s','.',0};
431 static const WCHAR format[] =
432 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
433 static const WCHAR Query_t[] =
434 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
435 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
436 ' ','\'','%','s','\'',0};
437 WCHAR message[1024];
438 WCHAR timet[0x100];
439 UINT rc;
440 MSIHANDLE view;
441 MSIHANDLE row = 0;
442 WCHAR *ActionText=NULL;
443 DWORD sz;
444 WCHAR Query[1024];
445 MSIHANDLE db;
447 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
449 sprintfW(Query,Query_t,action);
450 db = MsiGetActiveDatabase(hPackage);
451 rc = MsiDatabaseOpenViewW(db, Query, &view);
452 MsiCloseHandle(db);
453 MsiViewExecute(view, 0);
454 rc = MsiViewFetch(view,&row);
455 if (rc != ERROR_SUCCESS)
457 MsiViewClose(view);
458 MsiCloseHandle(view);
459 return;
462 sz = 0;
463 MsiRecordGetStringW(row,2,NULL,&sz);
464 sz++;
465 ActionText = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
466 MsiRecordGetStringW(row,2,ActionText,&sz);
467 MsiCloseHandle(row);
468 MsiViewClose(view);
469 MsiCloseHandle(view);
471 sprintfW(message,template_s,timet,action,ActionText);
473 row = MsiCreateRecord(1);
474 MsiRecordSetStringW(row,1,message);
476 MsiProcessMessage(hPackage, INSTALLMESSAGE_ACTIONSTART, row);
477 MsiCloseHandle(row);
478 HeapFree(GetProcessHeap(),0,ActionText);
481 static void ui_actioninfo(MSIHANDLE hPackage, LPCWSTR action, BOOL start,
482 UINT rc)
484 MSIHANDLE row;
485 static const WCHAR template_s[]=
486 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ','%','s',
487 '.',0};
488 static const WCHAR template_e[]=
489 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ','%','s',
490 '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ','%','i','.',0};
491 static const WCHAR format[] =
492 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
493 WCHAR message[1024];
494 WCHAR timet[0x100];
496 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
497 if (start)
498 sprintfW(message,template_s,timet,action);
499 else
500 sprintfW(message,template_e,timet,action,rc);
502 row = MsiCreateRecord(1);
503 MsiRecordSetStringW(row,1,message);
505 MsiProcessMessage(hPackage, INSTALLMESSAGE_INFO, row);
506 MsiCloseHandle(row);
509 /****************************************************
510 * TOP level entry points
511 *****************************************************/
513 UINT ACTION_DoTopLevelINSTALL(MSIHANDLE hPackage, LPCWSTR szPackagePath,
514 LPCWSTR szCommandLine)
516 DWORD sz;
517 CHAR buffer[10];
518 UINT rc;
520 if (szPackagePath)
522 LPWSTR p;
523 WCHAR check[MAX_PATH];
524 WCHAR pth[MAX_PATH];
525 DWORD size;
527 strcpyW(pth,szPackagePath);
528 p = strrchrW(pth,'\\');
529 if (p)
531 p++;
532 *p=0;
535 size = MAX_PATH;
536 if (MsiGetPropertyW(hPackage,cszSourceDir,check,&size)
537 != ERROR_SUCCESS )
538 MsiSetPropertyW(hPackage, cszSourceDir, pth);
541 if (szCommandLine)
543 LPWSTR ptr,ptr2;
544 ptr = (LPWSTR)szCommandLine;
546 while (*ptr)
548 WCHAR prop[0x100];
549 WCHAR val[0x100];
551 TRACE("Looking at %s\n",debugstr_w(ptr));
553 ptr2 = strchrW(ptr,'=');
554 if (ptr2)
556 BOOL quote=FALSE;
557 DWORD len = 0;
558 strncpyW(prop,ptr,ptr2-ptr);
559 prop[ptr2-ptr]=0;
560 ptr2++;
562 ptr = ptr2;
563 while (*ptr && (quote || (!quote && *ptr!=' ')))
565 if (*ptr == '"')
566 quote = !quote;
567 ptr++;
568 len++;
571 if (*ptr2=='"')
573 ptr2++;
574 len -= 2;
576 strncpyW(val,ptr2,len);
577 val[len]=0;
579 if (*ptr)
580 ptr++;
582 TRACE("Found commandline property (%s) = (%s)\n", debugstr_w(prop),
583 debugstr_w(val));
584 MsiSetPropertyW(hPackage,prop,val);
588 sz = 10;
589 if (MsiGetPropertyA(hPackage,"UILevel",buffer,&sz) == ERROR_SUCCESS)
591 if (atoi(buffer) >= INSTALLUILEVEL_REDUCED)
593 rc = ACTION_ProcessUISequence(hPackage);
594 if (rc == ERROR_SUCCESS)
595 rc = ACTION_ProcessExecSequence(hPackage,TRUE);
597 else
598 rc = ACTION_ProcessExecSequence(hPackage,FALSE);
600 else
601 rc = ACTION_ProcessExecSequence(hPackage,FALSE);
603 return rc;
607 static UINT ACTION_ProcessExecSequence(MSIHANDLE hPackage, BOOL UIran)
609 MSIHANDLE view;
610 UINT rc;
611 static const CHAR *ExecSeqQuery =
612 "select * from InstallExecuteSequence where Sequence > %i order by Sequence";
613 CHAR Query[1024];
614 MSIHANDLE db;
615 MSIHANDLE row = 0;
617 db = MsiGetActiveDatabase(hPackage);
619 if (UIran)
621 INT seq = 0;
622 static const CHAR *IVQuery =
623 "select Sequence from InstallExecuteSequence where Action = `InstallValidate`" ;
625 MsiDatabaseOpenViewA(db, IVQuery, &view);
626 MsiViewExecute(view, 0);
627 MsiViewFetch(view,&row);
628 seq = MsiRecordGetInteger(row,1);
629 MsiCloseHandle(row);
630 MsiViewClose(view);
631 MsiCloseHandle(view);
632 sprintf(Query,ExecSeqQuery,0);
634 else
635 sprintf(Query,ExecSeqQuery,0);
637 rc = MsiDatabaseOpenViewA(db, Query, &view);
638 MsiCloseHandle(db);
640 if (rc == ERROR_SUCCESS)
642 rc = MsiViewExecute(view, 0);
644 if (rc != ERROR_SUCCESS)
646 MsiViewClose(view);
647 MsiCloseHandle(view);
648 goto end;
651 TRACE("Running the actions \n");
653 while (1)
655 WCHAR buffer[0x100];
656 DWORD sz = 0x100;
658 rc = MsiViewFetch(view,&row);
659 if (rc != ERROR_SUCCESS)
661 rc = ERROR_SUCCESS;
662 break;
665 /* check conditions */
666 if (!MsiRecordIsNull(row,2))
668 sz=0x100;
669 rc = MsiRecordGetStringW(row,2,buffer,&sz);
670 if (rc != ERROR_SUCCESS)
672 MsiCloseHandle(row);
673 break;
676 /* this is a hack to skip errors in the condition code */
677 if (MsiEvaluateConditionW(hPackage, buffer) ==
678 MSICONDITION_FALSE)
680 MsiCloseHandle(row);
681 continue;
686 sz=0x100;
687 rc = MsiRecordGetStringW(row,1,buffer,&sz);
688 if (rc != ERROR_SUCCESS)
690 ERR("Error is %x\n",rc);
691 MsiCloseHandle(row);
692 break;
695 rc = ACTION_PerformAction(hPackage,buffer);
697 if (rc != ERROR_SUCCESS)
699 ERR("Execution halted due to error (%i)\n",rc);
700 MsiCloseHandle(row);
701 break;
704 MsiCloseHandle(row);
707 MsiViewClose(view);
708 MsiCloseHandle(view);
711 end:
712 return rc;
716 static UINT ACTION_ProcessUISequence(MSIHANDLE hPackage)
718 MSIHANDLE view;
719 UINT rc;
720 static const CHAR *ExecSeqQuery =
721 "select * from InstallUISequence where Sequence > 0 order by Sequence";
722 MSIHANDLE db;
724 db = MsiGetActiveDatabase(hPackage);
725 rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
726 MsiCloseHandle(db);
728 if (rc == ERROR_SUCCESS)
730 rc = MsiViewExecute(view, 0);
732 if (rc != ERROR_SUCCESS)
734 MsiViewClose(view);
735 MsiCloseHandle(view);
736 goto end;
739 TRACE("Running the actions \n");
741 while (1)
743 WCHAR buffer[0x100];
744 DWORD sz = 0x100;
745 MSIHANDLE row = 0;
747 rc = MsiViewFetch(view,&row);
748 if (rc != ERROR_SUCCESS)
750 rc = ERROR_SUCCESS;
751 break;
754 /* check conditions */
755 if (!MsiRecordIsNull(row,2))
757 sz=0x100;
758 rc = MsiRecordGetStringW(row,2,buffer,&sz);
759 if (rc != ERROR_SUCCESS)
761 MsiCloseHandle(row);
762 break;
765 if (MsiEvaluateConditionW(hPackage, buffer) ==
766 MSICONDITION_FALSE)
768 MsiCloseHandle(row);
769 continue;
774 sz=0x100;
775 rc = MsiRecordGetStringW(row,1,buffer,&sz);
776 if (rc != ERROR_SUCCESS)
778 ERR("Error is %x\n",rc);
779 MsiCloseHandle(row);
780 break;
783 rc = ACTION_PerformAction(hPackage,buffer);
785 if (rc != ERROR_SUCCESS)
787 ERR("Execution halted due to error (%i)\n",rc);
788 MsiCloseHandle(row);
789 break;
792 MsiCloseHandle(row);
795 MsiViewClose(view);
796 MsiCloseHandle(view);
799 end:
800 return rc;
803 /********************************************************
804 * ACTION helper functions and functions that perform the actions
805 *******************************************************/
808 * Alot of actions are really important even if they don't do anything
809 * explicit.. Lots of properties are set at the beginning of the installation
810 * CostFinalize does a bunch of work to translated the directories and such
812 * But until I get write access to the database that is hard, so I am going to
813 * hack it to see if I can get something to run.
815 UINT ACTION_PerformAction(MSIHANDLE hPackage, const WCHAR *action)
817 UINT rc = ERROR_SUCCESS;
819 TRACE("Performing action (%s)\n",debugstr_w(action));
820 ui_actioninfo(hPackage, action, TRUE, 0);
821 ui_actionstart(hPackage, action);
822 ui_progress(hPackage,2,1,0,0);
824 /* pre install, setup and configureation block */
825 if (strcmpW(action,szLaunchConditions)==0)
826 rc = ACTION_LaunchConditions(hPackage);
827 else if (strcmpW(action,szCostInitialize)==0)
828 rc = ACTION_CostInitialize(hPackage);
829 else if (strcmpW(action,szFileCost)==0)
830 rc = ACTION_FileCost(hPackage);
831 else if (strcmpW(action,szCostFinalize)==0)
832 rc = ACTION_CostFinalize(hPackage);
833 else if (strcmpW(action,szInstallValidate)==0)
834 rc = ACTION_InstallValidate(hPackage);
836 /* install block */
837 else if (strcmpW(action,szProcessComponents)==0)
838 rc = ACTION_ProcessComponents(hPackage);
839 else if (strcmpW(action,szInstallInitialize)==0)
840 rc = ACTION_InstallInitialize(hPackage);
841 else if (strcmpW(action,szCreateFolders)==0)
842 rc = ACTION_CreateFolders(hPackage);
843 else if (strcmpW(action,szInstallFiles)==0)
844 rc = ACTION_InstallFiles(hPackage);
845 else if (strcmpW(action,szDuplicateFiles)==0)
846 rc = ACTION_DuplicateFiles(hPackage);
847 else if (strcmpW(action,szWriteRegistryValues)==0)
848 rc = ACTION_WriteRegistryValues(hPackage);
849 else if (strcmpW(action,szRegisterTypeLibraries)==0)
850 rc = ACTION_RegisterTypeLibraries(hPackage);
851 else if (strcmpW(action,szRegisterClassInfo)==0)
852 rc = ACTION_RegisterClassInfo(hPackage);
853 else if (strcmpW(action,szRegisterProgIdInfo)==0)
854 rc = ACTION_RegisterProgIdInfo(hPackage);
857 Current called during itunes but unimplemented and seem important
859 ResolveSource (sets SourceDir)
860 CreateShortcuts (would be nice to have soon)
861 RegisterProduct
862 InstallFinalize
864 else if ((rc = ACTION_CustomAction(hPackage,action)) != ERROR_SUCCESS)
866 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
867 rc = ERROR_SUCCESS;
870 ui_actioninfo(hPackage, action, FALSE, rc);
871 return rc;
875 static UINT ACTION_CustomAction(MSIHANDLE hPackage,const WCHAR *action)
877 UINT rc = ERROR_SUCCESS;
878 MSIHANDLE view;
879 MSIHANDLE row = 0;
880 WCHAR ExecSeqQuery[1024] =
881 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','C','u','s','t','o'
882 ,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i'
883 ,'o','n','`',' ','=',' ','`',0};
884 static const WCHAR end[]={'`',0};
885 UINT type;
886 DWORD sz;
887 WCHAR source[0x100];
888 WCHAR target[0x200];
889 WCHAR *deformated=NULL;
890 MSIHANDLE db;
892 strcatW(ExecSeqQuery,action);
893 strcatW(ExecSeqQuery,end);
895 db = MsiGetActiveDatabase(hPackage);
896 rc = MsiDatabaseOpenViewW(db, ExecSeqQuery, &view);
897 MsiCloseHandle(db);
899 if (rc != ERROR_SUCCESS)
900 return rc;
902 rc = MsiViewExecute(view, 0);
903 if (rc != ERROR_SUCCESS)
905 MsiViewClose(view);
906 MsiCloseHandle(view);
907 return rc;
910 rc = MsiViewFetch(view,&row);
911 if (rc != ERROR_SUCCESS)
913 MsiViewClose(view);
914 MsiCloseHandle(view);
915 return rc;
918 type = MsiRecordGetInteger(row,2);
920 sz=0x100;
921 MsiRecordGetStringW(row,3,source,&sz);
922 sz=0x200;
923 MsiRecordGetStringW(row,4,target,&sz);
925 TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type,
926 debugstr_w(source), debugstr_w(target));
928 /* we are ignoring ALOT of flags and important synchronization stuff */
929 switch (type & CUSTOM_ACTION_TYPE_MASK)
931 case 1: /* DLL file stored in a Binary table stream */
932 rc = HANDLE_CustomType1(hPackage,source,target,type);
933 break;
934 case 2: /* Exe file stored in a Binary table strem */
935 rc = HANDLE_CustomType2(hPackage,source,target,type);
936 break;
937 case 35: /* Directory set with formatted text. */
938 case 51: /* Property set with formatted text. */
939 deformat_string(hPackage,target,&deformated);
940 rc = MsiSetPropertyW(hPackage,source,deformated);
941 HeapFree(GetProcessHeap(),0,deformated);
942 break;
943 default:
944 FIXME("UNHANDLED ACTION TYPE %i (%s %s)\n",
945 type & CUSTOM_ACTION_TYPE_MASK, debugstr_w(source),
946 debugstr_w(target));
949 MsiCloseHandle(row);
950 MsiViewClose(view);
951 MsiCloseHandle(view);
952 return rc;
955 static UINT store_binary_to_temp(MSIHANDLE hPackage, const LPWSTR source,
956 LPWSTR tmp_file)
958 DWORD sz=MAX_PATH;
960 if (MsiGetPropertyW(hPackage, cszTempFolder, tmp_file, &sz)
961 != ERROR_SUCCESS)
962 GetTempPathW(MAX_PATH,tmp_file);
964 strcatW(tmp_file,source);
966 if (GetFileAttributesW(tmp_file) != INVALID_FILE_ATTRIBUTES)
968 TRACE("File already exists\n");
969 return ERROR_SUCCESS;
971 else
973 /* write out the file */
974 UINT rc;
975 MSIHANDLE view;
976 MSIHANDLE row = 0;
977 WCHAR Query[1024] =
978 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','B','i'
979 ,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`',0};
980 static const WCHAR end[]={'`',0};
981 HANDLE the_file;
982 CHAR buffer[1024];
983 MSIHANDLE db;
985 if (track_tempfile(hPackage, source, tmp_file)!=0)
986 FIXME("File Name in temp tracking collision\n");
988 the_file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
989 FILE_ATTRIBUTE_NORMAL, NULL);
991 if (the_file == INVALID_HANDLE_VALUE)
992 return ERROR_FUNCTION_FAILED;
994 strcatW(Query,source);
995 strcatW(Query,end);
997 db = MsiGetActiveDatabase(hPackage);
998 rc = MsiDatabaseOpenViewW(db, Query, &view);
999 MsiCloseHandle(db);
1001 if (rc != ERROR_SUCCESS)
1002 return rc;
1004 rc = MsiViewExecute(view, 0);
1005 if (rc != ERROR_SUCCESS)
1007 MsiViewClose(view);
1008 MsiCloseHandle(view);
1009 return rc;
1012 rc = MsiViewFetch(view,&row);
1013 if (rc != ERROR_SUCCESS)
1015 MsiViewClose(view);
1016 MsiCloseHandle(view);
1017 return rc;
1022 DWORD write;
1023 sz = 1024;
1024 rc = MsiRecordReadStream(row,2,buffer,&sz);
1025 if (rc != ERROR_SUCCESS)
1027 ERR("Failed to get stream\n");
1028 CloseHandle(the_file);
1029 DeleteFileW(tmp_file);
1030 break;
1032 WriteFile(the_file,buffer,sz,&write,NULL);
1033 } while (sz == 1024);
1035 CloseHandle(the_file);
1037 MsiCloseHandle(row);
1038 MsiViewClose(view);
1039 MsiCloseHandle(view);
1042 return ERROR_SUCCESS;
1046 typedef UINT CustomEntry(MSIHANDLE);
1048 static UINT HANDLE_CustomType1(MSIHANDLE hPackage, const LPWSTR source,
1049 const LPWSTR target, const INT type)
1051 WCHAR tmp_file[MAX_PATH];
1052 CustomEntry *fn;
1053 HANDLE DLL;
1054 LPSTR proc;
1056 store_binary_to_temp(hPackage, source, tmp_file);
1058 TRACE("Calling function %s from %s\n",debugstr_w(target),
1059 debugstr_w(tmp_file));
1061 if (type & 0xc0)
1063 FIXME("Asynchronous execution.. UNHANDLED\n");
1064 return ERROR_SUCCESS;
1067 if (!strchrW(tmp_file,'.'))
1069 static const WCHAR dot[]={'.',0};
1070 strcatW(tmp_file,dot);
1073 DLL = LoadLibraryW(tmp_file);
1074 if (DLL)
1076 proc = strdupWtoA( target );
1077 fn = (CustomEntry*)GetProcAddress(DLL,proc);
1078 if (fn)
1080 TRACE("Calling function\n");
1081 fn(hPackage);
1083 else
1084 ERR("Cannot load functon\n");
1086 HeapFree(GetProcessHeap(),0,proc);
1087 FreeLibrary(DLL);
1089 else
1090 ERR("Unable to load library\n");
1092 return ERROR_SUCCESS;
1095 static UINT HANDLE_CustomType2(MSIHANDLE hPackage, const LPWSTR source,
1096 const LPWSTR target, const INT type)
1098 WCHAR tmp_file[MAX_PATH*2];
1099 STARTUPINFOW si;
1100 PROCESS_INFORMATION info;
1101 BOOL rc;
1102 WCHAR *deformated;
1103 static const WCHAR spc[] = {' ',0};
1105 memset(&si,0,sizeof(STARTUPINFOW));
1106 memset(&info,0,sizeof(PROCESS_INFORMATION));
1108 store_binary_to_temp(hPackage, source, tmp_file);
1110 strcatW(tmp_file,spc);
1111 deformat_string(hPackage,target,&deformated);
1112 strcatW(tmp_file,deformated);
1114 HeapFree(GetProcessHeap(),0,deformated);
1116 TRACE("executing exe %s \n",debugstr_w(tmp_file));
1118 rc = CreateProcessW(NULL, tmp_file, NULL, NULL, FALSE, 0, NULL,
1119 c_collen, &si, &info);
1121 if ( !rc )
1123 ERR("Unable to execute command\n");
1124 return ERROR_SUCCESS;
1127 if (!(type & 0xc0))
1128 WaitForSingleObject(info.hProcess,INFINITE);
1130 return ERROR_SUCCESS;
1133 /***********************************************************************
1134 * create_full_pathW
1136 * Recursively create all directories in the path.
1138 * shamelessly stolen from setupapi/queue.c
1140 static BOOL create_full_pathW(const WCHAR *path)
1142 BOOL ret = TRUE;
1143 int len;
1144 WCHAR *new_path;
1146 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *
1147 sizeof(WCHAR));
1148 strcpyW(new_path, path);
1150 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
1151 new_path[len - 1] = 0;
1153 while(!CreateDirectoryW(new_path, NULL))
1155 WCHAR *slash;
1156 DWORD last_error = GetLastError();
1157 if(last_error == ERROR_ALREADY_EXISTS)
1158 break;
1160 if(last_error != ERROR_PATH_NOT_FOUND)
1162 ret = FALSE;
1163 break;
1166 if(!(slash = strrchrW(new_path, '\\')))
1168 ret = FALSE;
1169 break;
1172 len = slash - new_path;
1173 new_path[len] = 0;
1174 if(!create_full_pathW(new_path))
1176 ret = FALSE;
1177 break;
1179 new_path[len] = '\\';
1182 HeapFree(GetProcessHeap(), 0, new_path);
1183 return ret;
1187 * Also we cannot enable/disable components either, so for now I am just going
1188 * to do all the directories for all the components.
1190 static UINT ACTION_CreateFolders(MSIHANDLE hPackage)
1192 static const CHAR *ExecSeqQuery = "select Directory_ from CreateFolder";
1193 UINT rc;
1194 MSIHANDLE view;
1195 MSIHANDLE db;
1196 MSIFOLDER *folder;
1198 db = MsiGetActiveDatabase(hPackage);
1199 rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
1200 MsiCloseHandle(db);
1202 if (rc != ERROR_SUCCESS)
1203 return rc;
1205 rc = MsiViewExecute(view, 0);
1206 if (rc != ERROR_SUCCESS)
1208 MsiViewClose(view);
1209 MsiCloseHandle(view);
1210 return rc;
1213 while (1)
1215 WCHAR dir[0x100];
1216 WCHAR full_path[MAX_PATH];
1217 DWORD sz;
1218 MSIHANDLE row = 0;
1219 MSIHANDLE uirow;
1221 rc = MsiViewFetch(view,&row);
1222 if (rc != ERROR_SUCCESS)
1224 rc = ERROR_SUCCESS;
1225 break;
1228 sz=0x100;
1229 rc = MsiRecordGetStringW(row,1,dir,&sz);
1231 if (rc!= ERROR_SUCCESS)
1233 ERR("Unable to get folder id \n");
1234 MsiCloseHandle(row);
1235 continue;
1238 sz = MAX_PATH;
1239 rc = resolve_folder(hPackage,dir,full_path,FALSE,FALSE,&folder);
1241 if (rc != ERROR_SUCCESS)
1243 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1244 MsiCloseHandle(row);
1245 continue;
1248 TRACE("Folder is %s\n",debugstr_w(full_path));
1250 /* UI stuff */
1251 uirow = MsiCreateRecord(1);
1252 MsiRecordSetStringW(uirow,1,full_path);
1253 ui_actiondata(hPackage,szCreateFolders,uirow);
1254 MsiCloseHandle(uirow);
1256 if (folder->State == 0)
1257 create_full_pathW(full_path);
1259 folder->State = 3;
1261 MsiCloseHandle(row);
1263 MsiViewClose(view);
1264 MsiCloseHandle(view);
1266 return rc;
1269 static int load_component(MSIPACKAGE* package, MSIHANDLE row)
1271 int index = package->loaded_components;
1272 DWORD sz;
1274 /* fill in the data */
1276 package->loaded_components++;
1277 if (package->loaded_components == 1)
1278 package->components = HeapAlloc(GetProcessHeap(),0,
1279 sizeof(MSICOMPONENT));
1280 else
1281 package->components = HeapReAlloc(GetProcessHeap(),0,
1282 package->components, package->loaded_components *
1283 sizeof(MSICOMPONENT));
1285 memset(&package->components[index],0,sizeof(MSICOMPONENT));
1287 sz = 96;
1288 MsiRecordGetStringW(row,1,package->components[index].Component,&sz);
1290 TRACE("Loading Component %s\n",
1291 debugstr_w(package->components[index].Component));
1293 sz = 0x100;
1294 if (!MsiRecordIsNull(row,2))
1295 MsiRecordGetStringW(row,2,package->components[index].ComponentId,&sz);
1297 sz = 96;
1298 MsiRecordGetStringW(row,3,package->components[index].Directory,&sz);
1300 package->components[index].Attributes = MsiRecordGetInteger(row,4);
1302 sz = 0x100;
1303 MsiRecordGetStringW(row,5,package->components[index].Condition,&sz);
1305 sz = 96;
1306 MsiRecordGetStringW(row,6,package->components[index].KeyPath,&sz);
1308 package->components[index].State = INSTALLSTATE_UNKNOWN;
1309 package->components[index].Enabled = TRUE;
1310 package->components[index].FeatureState= FALSE;
1312 return index;
1315 static void load_feature(MSIPACKAGE* package, MSIHANDLE row)
1317 int index = package->loaded_features;
1318 DWORD sz;
1319 static const WCHAR Query1[] = {'S','E','L','E','C','T',' ','C','o','m','p',
1320 'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',
1321 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',
1322 'a','t','u','r','e','_','=','\'','%','s','\'',0};
1323 static const WCHAR Query2[] = {'S','E','L','E','C','T',' ','*',' ','F','R',
1324 'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',
1325 'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};
1326 WCHAR Query[1024];
1327 MSIHANDLE view;
1328 MSIHANDLE view2;
1329 MSIHANDLE row2;
1330 MSIHANDLE row3;
1332 /* fill in the data */
1334 package->loaded_features ++;
1335 if (package->loaded_features == 1)
1336 package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE));
1337 else
1338 package->features = HeapReAlloc(GetProcessHeap(),0,package->features,
1339 package->loaded_features * sizeof(MSIFEATURE));
1341 memset(&package->features[index],0,sizeof(MSIFEATURE));
1343 sz = 96;
1344 MsiRecordGetStringW(row,1,package->features[index].Feature,&sz);
1346 TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature));
1348 sz = 96;
1349 if (!MsiRecordIsNull(row,2))
1350 MsiRecordGetStringW(row,2,package->features[index].Feature_Parent,&sz);
1352 sz = 0x100;
1353 if (!MsiRecordIsNull(row,3))
1354 MsiRecordGetStringW(row,3,package->features[index].Title,&sz);
1356 sz = 0x100;
1357 if (!MsiRecordIsNull(row,4))
1358 MsiRecordGetStringW(row,4,package->features[index].Description,&sz);
1360 if (!MsiRecordIsNull(row,5))
1361 package->features[index].Display = MsiRecordGetInteger(row,5);
1363 package->features[index].Level= MsiRecordGetInteger(row,6);
1365 sz = 96;
1366 if (!MsiRecordIsNull(row,7))
1367 MsiRecordGetStringW(row,7,package->features[index].Directory,&sz);
1369 package->features[index].Attributes= MsiRecordGetInteger(row,8);
1370 package->features[index].State = INSTALLSTATE_UNKNOWN;
1372 /* load feature components */
1374 sprintfW(Query,Query1,package->features[index].Feature);
1375 MsiDatabaseOpenViewW(package->db,Query,&view);
1376 MsiViewExecute(view,0);
1377 while (1)
1379 DWORD sz = 0x100;
1380 WCHAR buffer[0x100];
1381 DWORD rc;
1382 INT c_indx;
1383 INT cnt = package->features[index].ComponentCount;
1385 rc = MsiViewFetch(view,&row2);
1386 if (rc != ERROR_SUCCESS)
1387 break;
1389 sz = 0x100;
1390 MsiRecordGetStringW(row2,1,buffer,&sz);
1392 /* check to see if the component is already loaded */
1393 c_indx = get_loaded_component(package,buffer);
1394 if (c_indx != -1)
1396 TRACE("Component %s already loaded at %i\n", debugstr_w(buffer),
1397 c_indx);
1398 package->features[index].Components[cnt] = c_indx;
1399 package->features[index].ComponentCount ++;
1402 sprintfW(Query,Query2,buffer);
1404 MsiDatabaseOpenViewW(package->db,Query,&view2);
1405 MsiViewExecute(view2,0);
1406 while (1)
1408 DWORD rc;
1410 rc = MsiViewFetch(view2,&row3);
1411 if (rc != ERROR_SUCCESS)
1412 break;
1413 c_indx = load_component(package,row3);
1414 MsiCloseHandle(row3);
1416 package->features[index].Components[cnt] = c_indx;
1417 package->features[index].ComponentCount ++;
1419 MsiViewClose(view2);
1420 MsiCloseHandle(view2);
1421 MsiCloseHandle(row2);
1423 MsiViewClose(view);
1424 MsiCloseHandle(view);
1428 * I am not doing any of the costing functionality yet.
1429 * Mostly looking at doing the Component and Feature loading
1431 * The native MSI does ALOT of modification to tables here. Mostly adding alot
1432 * of temporary columns to the Feature and Component tables.
1434 * note: native msi also tracks the short filename. but i am only going to
1435 * track the long ones. Also looking at this directory table
1436 * it appears that the directory table does not get the parents
1437 * resolved base on property only based on their entrys in the
1438 * directory table.
1440 static UINT ACTION_CostInitialize(MSIHANDLE hPackage)
1442 MSIHANDLE view;
1443 MSIHANDLE row;
1444 DWORD sz;
1445 MSIPACKAGE *package;
1447 static const CHAR Query_all[] = "SELECT * FROM Feature";
1449 MsiSetPropertyA(hPackage,"CostingComplete","0");
1450 MsiSetPropertyW(hPackage, cszRootDrive , c_collen);
1452 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
1454 sz = 0x100;
1455 MsiDatabaseOpenViewA(package->db,Query_all,&view);
1456 MsiViewExecute(view,0);
1457 while (1)
1459 DWORD rc;
1461 rc = MsiViewFetch(view,&row);
1462 if (rc != ERROR_SUCCESS)
1463 break;
1465 load_feature(package,row);
1466 MsiCloseHandle(row);
1468 MsiViewClose(view);
1469 MsiCloseHandle(view);
1471 return ERROR_SUCCESS;
1474 static int load_file(MSIPACKAGE* package, MSIHANDLE row)
1476 int index = package->loaded_files;
1477 int i;
1478 WCHAR buffer[0x100];
1479 DWORD sz;
1481 /* fill in the data */
1483 package->loaded_files++;
1484 if (package->loaded_files== 1)
1485 package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
1486 else
1487 package->files = HeapReAlloc(GetProcessHeap(),0,
1488 package->files , package->loaded_files * sizeof(MSIFILE));
1490 memset(&package->files[index],0,sizeof(MSIFILE));
1492 sz = 72;
1493 MsiRecordGetStringW(row,1,package->files[index].File,&sz);
1495 sz = 0x100;
1496 MsiRecordGetStringW(row,2,buffer,&sz);
1498 package->files[index].ComponentIndex = -1;
1499 for (i = 0; i < package->loaded_components; i++)
1500 if (strcmpW(package->components[i].Component,buffer)==0)
1502 package->files[index].ComponentIndex = i;
1503 break;
1505 if (package->files[index].ComponentIndex == -1)
1506 ERR("Unfound Component %s\n",debugstr_w(buffer));
1508 sz = MAX_PATH;
1509 MsiRecordGetStringW(row,3,package->files[index].FileName,&sz);
1511 reduce_to_longfilename(package->files[index].FileName);
1513 package->files[index].FileSize = MsiRecordGetInteger(row,4);
1515 sz = 72;
1516 if (!MsiRecordIsNull(row,5))
1517 MsiRecordGetStringW(row,5,package->files[index].Version,&sz);
1519 sz = 20;
1520 if (!MsiRecordIsNull(row,6))
1521 MsiRecordGetStringW(row,6,package->files[index].Language,&sz);
1523 if (!MsiRecordIsNull(row,7))
1524 package->files[index].Attributes= MsiRecordGetInteger(row,7);
1526 package->files[index].Sequence= MsiRecordGetInteger(row,8);
1528 package->files[index].Temporary = FALSE;
1529 package->files[index].State = 0;
1531 TRACE("File Loaded (%s)\n",debugstr_w(package->files[index].File));
1533 return ERROR_SUCCESS;
1536 static UINT ACTION_FileCost(MSIHANDLE hPackage)
1538 MSIHANDLE view;
1539 MSIHANDLE row;
1540 MSIPACKAGE *package;
1541 UINT rc;
1542 static const CHAR Query[] = "SELECT * FROM File Order by Sequence";
1544 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
1545 if (!package)
1546 return ERROR_INVALID_HANDLE;
1548 rc = MsiDatabaseOpenViewA(package->db, Query, &view);
1549 if (rc != ERROR_SUCCESS)
1550 return rc;
1552 rc = MsiViewExecute(view, 0);
1553 if (rc != ERROR_SUCCESS)
1555 MsiViewClose(view);
1556 MsiCloseHandle(view);
1557 return rc;
1560 while (1)
1562 rc = MsiViewFetch(view,&row);
1563 if (rc != ERROR_SUCCESS)
1565 rc = ERROR_SUCCESS;
1566 break;
1568 load_file(package,row);
1569 MsiCloseHandle(row);
1571 MsiViewClose(view);
1572 MsiCloseHandle(view);
1574 return ERROR_SUCCESS;
1577 static INT load_folder(MSIHANDLE hPackage, const WCHAR* dir)
1580 WCHAR Query[1024] =
1581 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',
1582 't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',
1583 'o','r','y','`',' ','=',' ','`',0};
1584 static const WCHAR end[]={'`',0};
1585 UINT rc;
1586 MSIHANDLE view;
1587 WCHAR targetbuffer[0x100];
1588 WCHAR *srcdir = NULL;
1589 WCHAR *targetdir = NULL;
1590 WCHAR parent[0x100];
1591 DWORD sz=0x100;
1592 MSIHANDLE row = 0;
1593 MSIPACKAGE *package;
1594 INT i,index = -1;
1596 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
1598 TRACE("Looking for dir %s\n",debugstr_w(dir));
1600 for (i = 0; i < package->loaded_folders; i++)
1602 if (strcmpW(package->folders[i].Directory,dir)==0)
1604 TRACE(" %s retuning on index %i\n",debugstr_w(dir),i);
1605 return i;
1609 TRACE("Working to load %s\n",debugstr_w(dir));
1611 index = package->loaded_folders;
1613 package->loaded_folders++;
1614 if (package->loaded_folders== 1)
1615 package->folders = HeapAlloc(GetProcessHeap(),0,
1616 sizeof(MSIFOLDER));
1617 else
1618 package->folders= HeapReAlloc(GetProcessHeap(),0,
1619 package->folders, package->loaded_folders*
1620 sizeof(MSIFOLDER));
1622 memset(&package->folders[index],0,sizeof(MSIFOLDER));
1624 strcpyW(package->folders[index].Directory,dir);
1626 strcatW(Query,dir);
1627 strcatW(Query,end);
1629 rc = MsiDatabaseOpenViewW(package->db, Query, &view);
1631 if (rc != ERROR_SUCCESS)
1632 return -1;
1634 rc = MsiViewExecute(view, 0);
1635 if (rc != ERROR_SUCCESS)
1637 MsiViewClose(view);
1638 MsiCloseHandle(view);
1639 return -1;
1642 rc = MsiViewFetch(view,&row);
1643 if (rc != ERROR_SUCCESS)
1645 MsiViewClose(view);
1646 MsiCloseHandle(view);
1647 return -1;
1650 sz=0x100;
1651 MsiRecordGetStringW(row,3,targetbuffer,&sz);
1652 targetdir=targetbuffer;
1654 /* split src and target dir */
1655 if (strchrW(targetdir,':'))
1657 srcdir=strchrW(targetdir,':');
1658 *srcdir=0;
1659 srcdir ++;
1661 else
1662 srcdir=NULL;
1664 /* for now only pick long filename versions */
1665 if (strchrW(targetdir,'|'))
1667 targetdir = strchrW(targetdir,'|');
1668 *targetdir = 0;
1669 targetdir ++;
1671 if (srcdir && strchrW(srcdir,'|'))
1673 srcdir= strchrW(srcdir,'|');
1674 *srcdir= 0;
1675 srcdir ++;
1678 /* now check for root dirs */
1679 if (targetdir[0] == '.' && targetdir[1] == 0)
1680 targetdir = NULL;
1682 if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
1683 srcdir = NULL;
1685 if (targetdir)
1686 strcpyW(package->folders[index].TargetDefault,targetdir);
1688 if (srcdir)
1689 strcpyW(package->folders[index].SourceDefault,srcdir);
1690 else if (targetdir)
1691 strcpyW(package->folders[index].SourceDefault,targetdir);
1693 if (MsiRecordIsNull(row,2))
1694 parent[0]=0;
1695 else
1697 sz=0x100;
1698 MsiRecordGetStringW(row,2,parent,&sz);
1701 if (parent[0])
1703 i = load_folder(hPackage,parent);
1704 package->folders[index].ParentIndex = i;
1705 TRACE("Parent is index %i... %s %s\n",
1706 package->folders[index].ParentIndex,
1707 debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),
1708 debugstr_w(parent));
1710 else
1711 package->folders[index].ParentIndex = -2;
1713 sz = MAX_PATH;
1714 rc = MsiGetPropertyW(hPackage, dir, package->folders[index].Property, &sz);
1715 if (rc != ERROR_SUCCESS)
1716 package->folders[index].Property[0]=0;
1718 MsiCloseHandle(row);
1719 MsiViewClose(view);
1720 MsiCloseHandle(view);
1721 TRACE(" %s retuning on index %i\n",debugstr_w(dir),index);
1722 return index;
1725 static UINT resolve_folder(MSIHANDLE hPackage, LPCWSTR name, LPWSTR path,
1726 BOOL source, BOOL set_prop, MSIFOLDER **folder)
1728 MSIPACKAGE *package;
1729 INT i;
1730 UINT rc = ERROR_SUCCESS;
1731 DWORD sz;
1733 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
1735 TRACE("Working to resolve %s\n",debugstr_w(name));
1737 if (!path)
1738 return rc;
1740 /* special resolving for Target and Source root dir */
1741 if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
1743 if (!source)
1745 sz = MAX_PATH;
1746 rc = MsiGetPropertyW(hPackage,cszTargetDir,path,&sz);
1747 if (rc != ERROR_SUCCESS)
1749 sz = MAX_PATH;
1750 rc = MsiGetPropertyW(hPackage,cszRootDrive,path,&sz);
1751 if (set_prop)
1752 MsiSetPropertyW(hPackage,cszTargetDir,path);
1754 if (folder)
1755 *folder = &(package->folders[0]);
1756 return rc;
1758 else
1760 sz = MAX_PATH;
1761 rc = MsiGetPropertyW(hPackage,cszSourceDir,path,&sz);
1762 if (rc != ERROR_SUCCESS)
1764 sz = MAX_PATH;
1765 rc = MsiGetPropertyW(hPackage,cszDatabase,path,&sz);
1766 if (rc == ERROR_SUCCESS)
1768 LPWSTR ptr = strrchrW(path,'\\');
1769 if (ptr)
1771 ptr++;
1772 *ptr = 0;
1776 if (folder)
1777 *folder = &(package->folders[0]);
1778 return rc;
1782 for (i = 0; i < package->loaded_folders; i++)
1784 if (strcmpW(package->folders[i].Directory,name)==0)
1785 break;
1788 if (i >= package->loaded_folders)
1789 return ERROR_FUNCTION_FAILED;
1791 if (folder)
1792 *folder = &(package->folders[i]);
1794 if (!source && package->folders[i].ResolvedTarget[0])
1796 strcpyW(path,package->folders[i].ResolvedTarget);
1797 TRACE(" already resolved to %s\n",debugstr_w(path));
1798 return ERROR_SUCCESS;
1800 else if (source && package->folders[i].ResolvedSource[0])
1802 strcpyW(path,package->folders[i].ResolvedSource);
1803 return ERROR_SUCCESS;
1805 else if (!source && package->folders[i].Property[0])
1807 strcpyW(path,package->folders[i].Property);
1808 TRACE(" internally set to %s\n",debugstr_w(path));
1809 if (set_prop)
1810 MsiSetPropertyW(hPackage,name,path);
1811 return ERROR_SUCCESS;
1814 if (package->folders[i].ParentIndex >= 0)
1816 TRACE(" ! Parent is %s\n", debugstr_w(package->folders[
1817 package->folders[i].ParentIndex].Directory));
1818 resolve_folder(hPackage, package->folders[
1819 package->folders[i].ParentIndex].Directory, path,source,
1820 set_prop, NULL);
1822 if (!source)
1824 if (package->folders[i].TargetDefault[0])
1826 strcatW(path,package->folders[i].TargetDefault);
1827 strcatW(path,cszbs);
1829 strcpyW(package->folders[i].ResolvedTarget,path);
1830 TRACE(" resolved into %s\n",debugstr_w(path));
1831 if (set_prop)
1832 MsiSetPropertyW(hPackage,name,path);
1834 else
1836 if (package->folders[i].SourceDefault[0])
1838 strcatW(path,package->folders[i].SourceDefault);
1839 strcatW(path,cszbs);
1841 strcpyW(package->folders[i].ResolvedSource,path);
1844 return rc;
1848 * Alot is done in this function aside from just the costing.
1849 * The costing needs to be implemented at some point but for now I am going
1850 * to focus on the directory building
1853 static UINT ACTION_CostFinalize(MSIHANDLE hPackage)
1855 static const CHAR *ExecSeqQuery = "select * from Directory";
1856 static const CHAR *ConditionQuery = "select * from Condition";
1857 UINT rc;
1858 MSIHANDLE view;
1859 MSIPACKAGE *package;
1860 INT i;
1862 TRACE("Building Directory properties\n");
1864 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
1866 rc = MsiDatabaseOpenViewA(package->db, ExecSeqQuery, &view);
1868 if (rc != ERROR_SUCCESS)
1869 return rc;
1871 rc = MsiViewExecute(view, 0);
1872 if (rc != ERROR_SUCCESS)
1874 MsiViewClose(view);
1875 MsiCloseHandle(view);
1876 return rc;
1879 while (1)
1881 WCHAR name[0x100];
1882 WCHAR path[MAX_PATH];
1883 MSIHANDLE row = 0;
1884 DWORD sz;
1886 rc = MsiViewFetch(view,&row);
1888 if (rc != ERROR_SUCCESS)
1890 rc = ERROR_SUCCESS;
1891 break;
1894 sz=0x100;
1895 MsiRecordGetStringW(row,1,name,&sz);
1897 /* This helper function now does ALL the work */
1898 TRACE("Dir %s ...\n",debugstr_w(name));
1899 load_folder(hPackage,name);
1900 resolve_folder(hPackage,name,path,FALSE,TRUE,NULL);
1901 TRACE("resolves to %s\n",debugstr_w(path));
1903 MsiCloseHandle(row);
1905 MsiViewClose(view);
1906 MsiCloseHandle(view);
1908 TRACE("File calculations %i files\n",package->loaded_files);
1910 for (i = 0; i < package->loaded_files; i++)
1912 MSICOMPONENT* comp = NULL;
1913 MSIFILE* file= NULL;
1915 file = &package->files[i];
1916 if (file->ComponentIndex >= 0)
1917 comp = &package->components[file->ComponentIndex];
1919 if (comp)
1921 /* calculate target */
1922 resolve_folder(hPackage, comp->Directory, file->TargetPath, FALSE,
1923 FALSE, NULL);
1924 strcatW(file->TargetPath,file->FileName);
1926 TRACE("file %s resolves to %s\n",
1927 debugstr_w(file->File),debugstr_w(file->TargetPath));
1929 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1931 file->State = 1;
1932 comp->Cost += file->FileSize;
1934 else
1936 if (file->Version[0])
1938 DWORD handle;
1939 DWORD versize;
1940 UINT sz;
1941 LPVOID version;
1942 WCHAR filever[0x100];
1943 static const WCHAR name[] =
1944 {'\\','V','a','r','F','i','l','e','I','n','f','o',
1945 '\\','F','i','l','e','V','e','r','s','i','o','n',0};
1947 FIXME("Version comparison.. Untried Untested and most "
1948 "likely very very wrong\n");
1949 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1950 version = HeapAlloc(GetProcessHeap(),0,versize);
1951 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1952 sz = 0x100;
1953 VerQueryValueW(version,name,(LPVOID)filever,&sz);
1954 HeapFree(GetProcessHeap(),0,version);
1956 if (strcmpW(version,file->Version)<0)
1958 file->State = 2;
1959 FIXME("cost should be diff in size\n");
1960 comp->Cost += file->FileSize;
1962 else
1963 file->State = 3;
1965 else
1966 file->State = 3;
1971 TRACE("Evaluating Condition Table\n");
1973 rc = MsiDatabaseOpenViewA(package->db, ConditionQuery, &view);
1975 if (rc != ERROR_SUCCESS)
1976 return rc;
1978 rc = MsiViewExecute(view, 0);
1979 if (rc != ERROR_SUCCESS)
1981 MsiViewClose(view);
1982 MsiCloseHandle(view);
1983 return rc;
1986 while (1)
1988 WCHAR Feature[0x100];
1989 WCHAR Condition[0x100];
1990 MSIHANDLE row = 0;
1991 DWORD sz;
1992 int feature_index;
1994 rc = MsiViewFetch(view,&row);
1996 if (rc != ERROR_SUCCESS)
1998 rc = ERROR_SUCCESS;
1999 break;
2002 sz = 0x100;
2003 MsiRecordGetStringW(row,1,Feature,&sz);
2004 sz = 0x100;
2005 MsiRecordGetStringW(row,3,Condition,&sz);
2007 feature_index = get_loaded_feature(package,Feature);
2008 if (feature_index < 0)
2009 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));
2010 else
2012 if (MsiEvaluateConditionW(hPackage,Condition) == MSICONDITION_TRUE)
2014 int level = MsiRecordGetInteger(row,2);
2015 TRACE("Reseting feature %s to level %i\n",debugstr_w(Feature),
2016 level);
2017 package->features[feature_index].Level = level;
2021 MsiCloseHandle(row);
2023 MsiViewClose(view);
2024 MsiCloseHandle(view);
2026 TRACE("Enabling or Disabling Components\n");
2027 for (i = 0; i < package->loaded_components; i++)
2029 if (package->components[i].Condition[0])
2031 if (MsiEvaluateConditionW(hPackage,
2032 package->components[i].Condition) == MSICONDITION_FALSE)
2034 TRACE("Disabling component %s\n",
2035 debugstr_w(package->components[i].Component));
2036 package->components[i].Enabled = FALSE;
2041 MsiSetPropertyA(hPackage,"CostingComplete","1");
2042 return ERROR_SUCCESS;
2046 * This is a helper function for handling embedded cabinet media
2048 static UINT writeout_cabinet_stream(MSIHANDLE hPackage, WCHAR* stream_name,
2049 WCHAR* source)
2051 UINT rc;
2052 USHORT* data;
2053 UINT size;
2054 DWORD write;
2055 HANDLE the_file;
2056 MSIHANDLE db;
2057 WCHAR tmp[MAX_PATH];
2059 db = MsiGetActiveDatabase(hPackage);
2060 rc = read_raw_stream_data(db,stream_name,&data,&size);
2061 MsiCloseHandle(db);
2063 if (rc != ERROR_SUCCESS)
2064 return rc;
2066 write = MAX_PATH;
2067 if (MsiGetPropertyW(hPackage, cszTempFolder, tmp, &write))
2068 GetTempPathW(MAX_PATH,tmp);
2070 GetTempFileNameW(tmp,stream_name,0,source);
2072 track_tempfile(hPackage,strrchrW(source,'\\'), source);
2073 the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2074 FILE_ATTRIBUTE_NORMAL, NULL);
2076 if (the_file == INVALID_HANDLE_VALUE)
2078 rc = ERROR_FUNCTION_FAILED;
2079 goto end;
2082 WriteFile(the_file,data,size,&write,NULL);
2083 CloseHandle(the_file);
2084 TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
2085 end:
2086 HeapFree(GetProcessHeap(),0,data);
2087 return rc;
2091 /***********************************************************************
2092 * extract_cabinet_file
2094 * Extract files from a cab file.
2096 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
2098 static BOOL extract_cabinet_file_advpack( const WCHAR *cabinet,
2099 const WCHAR *root)
2101 static HMODULE advpack;
2103 char *cab_path, *cab_file;
2105 if (!pExtractFiles)
2107 if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
2109 ERR( "could not load advpack.dll\n" );
2110 return FALSE;
2112 if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles"
2115 ERR( "could not find ExtractFiles in advpack.dll\n" );
2116 return FALSE;
2120 if (!(cab_file = strdupWtoA( cabinet ))) return FALSE;
2121 if (!(cab_path = strdupWtoA( root ))) return FALSE;
2123 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
2124 pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
2125 HeapFree( GetProcessHeap(), 0, cab_file );
2126 HeapFree( GetProcessHeap(), 0, cab_path );
2127 return TRUE;
2130 static BOOL extract_cabinet_file_cabinet( const WCHAR *cabinet,
2131 const WCHAR *root)
2134 /* from cabinet.h */
2136 struct ExtractFileList {
2137 LPSTR filename;
2138 struct ExtractFileList *next;
2139 BOOL unknown; /* always 1L */
2142 typedef struct {
2143 long result1; /* 0x000 */
2144 long unknown1[3]; /* 0x004 */
2145 struct ExtractFileList* filelist; /* 0x010 */
2146 long filecount; /* 0x014 */
2147 long unknown2; /* 0x018 */
2148 char directory[0x104]; /* 0x01c */
2149 char lastfile[0x20c]; /* 0x120 */
2150 } EXTRACTdest;
2152 HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR what);
2154 char *cab_path, *src_path;
2155 EXTRACTdest exd;
2156 struct ExtractFileList fl;
2158 if (!(cab_path = strdupWtoA( cabinet ))) return FALSE;
2159 if (!(src_path = strdupWtoA( root ))) return FALSE;
2161 memset(&exd,0,sizeof(exd));
2162 strcpy(exd.directory,src_path);
2163 exd.unknown2 = 0x1;
2164 fl.filename = cab_path;
2165 fl.next = NULL;
2166 fl.unknown = 1;
2167 exd.filelist = &fl;
2168 FIXME( "more aweful hack: extracting cabinet %s\n", debugstr_a(cab_path) );
2169 Extract(&exd,cab_path);
2171 HeapFree( GetProcessHeap(), 0, cab_path );
2172 HeapFree( GetProcessHeap(), 0, src_path );
2173 return TRUE;
2176 static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path)
2178 TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));
2179 if (!extract_cabinet_file_advpack(source,path))
2180 return extract_cabinet_file_cabinet(source,path);
2181 return TRUE;
2184 static UINT ready_media_for_file(MSIHANDLE hPackage, UINT sequence,
2185 WCHAR* path)
2187 UINT rc;
2188 MSIHANDLE view;
2189 MSIHANDLE row = 0;
2190 WCHAR source[MAX_PATH];
2191 static const CHAR *ExecSeqQuery =
2192 "select * from Media where LastSequence >= %i order by LastSequence";
2193 CHAR Query[1024];
2194 WCHAR cab[0x100];
2195 DWORD sz=0x100;
2196 INT seq;
2197 static INT last_sequence = 0;
2198 MSIHANDLE db;
2200 if (sequence <= last_sequence)
2202 TRACE("Media already ready (%i, %i)\n",sequence,last_sequence);
2203 return ERROR_SUCCESS;
2206 sprintf(Query,ExecSeqQuery,sequence);
2208 db = MsiGetActiveDatabase(hPackage);
2209 rc = MsiDatabaseOpenViewA(db, Query, &view);
2210 MsiCloseHandle(db);
2212 if (rc != ERROR_SUCCESS)
2213 return rc;
2215 rc = MsiViewExecute(view, 0);
2216 if (rc != ERROR_SUCCESS)
2218 MsiViewClose(view);
2219 MsiCloseHandle(view);
2220 return rc;
2223 rc = MsiViewFetch(view,&row);
2224 if (rc != ERROR_SUCCESS)
2226 MsiViewClose(view);
2227 MsiCloseHandle(view);
2228 return rc;
2230 seq = MsiRecordGetInteger(row,2);
2231 last_sequence = seq;
2233 if (!MsiRecordIsNull(row,4))
2235 sz=0x100;
2236 MsiRecordGetStringW(row,4,cab,&sz);
2237 TRACE("Source is CAB %s\n",debugstr_w(cab));
2238 /* the stream does not contain the # character */
2239 if (cab[0]=='#')
2241 writeout_cabinet_stream(hPackage,&cab[1],source);
2242 strcpyW(path,source);
2243 *(strrchrW(path,'\\')+1)=0;
2245 else
2247 sz = 0x100;
2248 if (MsiGetPropertyW(hPackage, cszSourceDir, source, &sz))
2250 ERR("No Source dir defined \n");
2251 rc = ERROR_FUNCTION_FAILED;
2253 else
2255 strcpyW(path,source);
2256 strcatW(source,cab);
2257 /* extract the cab file into a folder in the temp folder */
2258 sz = MAX_PATH;
2259 if (MsiGetPropertyW(hPackage, cszTempFolder,path, &sz)
2260 != ERROR_SUCCESS)
2261 GetTempPathW(MAX_PATH,path);
2264 rc = !extract_cabinet_file(source,path);
2266 MsiCloseHandle(row);
2267 MsiViewClose(view);
2268 MsiCloseHandle(view);
2269 return rc;
2272 inline static UINT create_component_directory (MSIHANDLE hPackage, MSIPACKAGE*
2273 package, INT component)
2275 UINT rc;
2276 MSIFOLDER *folder;
2277 WCHAR install_path[MAX_PATH];
2279 rc = resolve_folder(hPackage, package->components[component].Directory,
2280 install_path, FALSE, FALSE, &folder);
2282 if (rc != ERROR_SUCCESS)
2283 return rc;
2285 /* create the path */
2286 if (folder->State == 0)
2288 create_full_pathW(install_path);
2289 folder->State = 2;
2292 return rc;
2295 static UINT ACTION_InstallFiles(MSIHANDLE hPackage)
2297 UINT rc = ERROR_SUCCESS;
2298 INT index;
2299 MSIPACKAGE *package;
2300 MSIHANDLE uirow;
2301 WCHAR uipath[MAX_PATH];
2303 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
2305 if (!package)
2306 return ERROR_INVALID_HANDLE;
2308 /* increment progress bar each time action data is sent */
2309 ui_progress(hPackage,1,1,1,0);
2311 for (index = 0; index < package->loaded_files; index++)
2313 WCHAR path_to_source[MAX_PATH];
2314 MSIFILE *file;
2316 file = &package->files[index];
2318 if (file->Temporary)
2319 continue;
2321 if (!package->components[file->ComponentIndex].Enabled ||
2322 !package->components[file->ComponentIndex].FeatureState)
2324 TRACE("File %s is not scheduled for install\n",
2325 debugstr_w(file->File));
2326 continue;
2329 if ((file->State == 1) || (file->State == 2))
2331 TRACE("Installing %s\n",debugstr_w(file->File));
2332 rc = ready_media_for_file(hPackage,file->Sequence,path_to_source);
2334 * WARNING!
2335 * our file table could change here because a new temp file
2336 * may have been created
2338 file = &package->files[index];
2339 if (rc != ERROR_SUCCESS)
2341 ERR("Unable to ready media\n");
2342 rc = ERROR_FUNCTION_FAILED;
2343 break;
2346 create_component_directory(hPackage, package, file->ComponentIndex);
2348 strcpyW(file->SourcePath, path_to_source);
2349 strcatW(file->SourcePath, file->File);
2351 TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
2352 debugstr_w(file->TargetPath));
2354 /* the UI chunk */
2355 uirow=MsiCreateRecord(9);
2356 MsiRecordSetStringW(uirow,1,file->File);
2357 strcpyW(uipath,file->TargetPath);
2358 *(strrchrW(uipath,'\\')+1)=0;
2359 MsiRecordSetStringW(uirow,9,uipath);
2360 MsiRecordSetInteger(uirow,6,file->FileSize);
2361 ui_actiondata(hPackage,szInstallFiles,uirow);
2362 MsiCloseHandle(uirow);
2364 rc = !MoveFileW(file->SourcePath,file->TargetPath);
2365 ui_progress(hPackage,2,0,0,0);
2367 if (rc)
2369 ERR("Unable to move file (error %li)\n",GetLastError());
2370 rc = ERROR_SUCCESS;
2372 else
2373 file->State = 4;
2377 return rc;
2380 inline static UINT get_file_target(MSIHANDLE hPackage, LPCWSTR file_key,
2381 LPWSTR file_source)
2383 MSIPACKAGE *package;
2384 INT index;
2386 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
2387 if (!package)
2388 return ERROR_INVALID_HANDLE;
2390 for (index = 0; index < package->loaded_files; index ++)
2392 if (strcmpW(file_key,package->files[index].File)==0)
2394 if (package->files[index].State >= 3)
2396 strcpyW(file_source,package->files[index].TargetPath);
2397 return ERROR_SUCCESS;
2399 else
2400 return ERROR_FILE_NOT_FOUND;
2404 return ERROR_FUNCTION_FAILED;
2407 static UINT ACTION_DuplicateFiles(MSIHANDLE hPackage)
2409 UINT rc;
2410 MSIHANDLE view;
2411 MSIHANDLE row = 0;
2412 static const CHAR *ExecSeqQuery = "select * from DuplicateFile";
2413 MSIPACKAGE* package;
2415 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
2416 if (!package)
2417 return ERROR_INVALID_HANDLE;
2419 rc = MsiDatabaseOpenViewA(package->db, ExecSeqQuery, &view);
2421 if (rc != ERROR_SUCCESS)
2422 return rc;
2424 rc = MsiViewExecute(view, 0);
2425 if (rc != ERROR_SUCCESS)
2427 MsiViewClose(view);
2428 MsiCloseHandle(view);
2429 return rc;
2432 while (1)
2434 WCHAR file_key[0x100];
2435 WCHAR file_source[MAX_PATH];
2436 WCHAR dest_name[0x100];
2437 WCHAR dest_path[MAX_PATH];
2438 WCHAR component[0x100];
2439 INT component_index;
2441 DWORD sz=0x100;
2443 rc = MsiViewFetch(view,&row);
2444 if (rc != ERROR_SUCCESS)
2446 rc = ERROR_SUCCESS;
2447 break;
2450 sz=0x100;
2451 rc = MsiRecordGetStringW(row,2,component,&sz);
2452 if (rc != ERROR_SUCCESS)
2454 ERR("Unable to get component\n");
2455 MsiCloseHandle(row);
2456 break;
2459 component_index = get_loaded_component(package,component);
2460 if (!package->components[component_index].Enabled ||
2461 !package->components[component_index].FeatureState)
2463 TRACE("Skipping copy due to disabled component\n");
2464 MsiCloseHandle(row);
2465 continue;
2468 sz=0x100;
2469 rc = MsiRecordGetStringW(row,3,file_key,&sz);
2470 if (rc != ERROR_SUCCESS)
2472 ERR("Unable to get file key\n");
2473 MsiCloseHandle(row);
2474 break;
2477 rc = get_file_target(hPackage,file_key,file_source);
2479 if (rc != ERROR_SUCCESS)
2481 ERR("Original file unknown %s\n",debugstr_w(file_key));
2482 MsiCloseHandle(row);
2483 break;
2486 if (MsiRecordIsNull(row,4))
2488 strcpyW(dest_name,strrchrW(file_source,'\\')+1);
2490 else
2492 sz=0x100;
2493 MsiRecordGetStringW(row,4,dest_name,&sz);
2494 reduce_to_longfilename(dest_name);
2497 if (MsiRecordIsNull(row,5))
2499 strcpyW(dest_path,file_source);
2500 *strrchrW(dest_path,'\\')=0;
2502 else
2504 WCHAR destkey[0x100];
2505 sz=0x100;
2506 MsiRecordGetStringW(row,5,destkey,&sz);
2507 sz = 0x100;
2508 rc = resolve_folder(hPackage, destkey, dest_path,FALSE,FALSE,NULL);
2509 if (rc != ERROR_SUCCESS)
2511 ERR("Unable to get destination folder\n");
2512 MsiCloseHandle(row);
2513 break;
2517 strcatW(dest_path,dest_name);
2519 TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
2520 debugstr_w(dest_path));
2522 if (strcmpW(file_source,dest_path))
2523 rc = !CopyFileW(file_source,dest_path,TRUE);
2524 else
2525 rc = ERROR_SUCCESS;
2527 if (rc != ERROR_SUCCESS)
2528 ERR("Failed to copy file\n");
2530 FIXME("We should track these duplicate files as well\n");
2532 MsiCloseHandle(row);
2534 MsiViewClose(view);
2535 MsiCloseHandle(view);
2536 return rc;
2541 /* OK this value is "interpretted" and then formatted based on the
2542 first few characters */
2543 static LPSTR parse_value(MSIHANDLE hPackage, WCHAR *value, DWORD *type,
2544 DWORD *size)
2546 LPSTR data = NULL;
2547 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2549 if (value[1]=='x')
2551 LPWSTR ptr;
2552 CHAR byte[5];
2553 LPWSTR deformated;
2554 int count;
2556 deformat_string(hPackage, &value[2], &deformated);
2558 /* binary value type */
2559 ptr = deformated;
2560 *type=REG_BINARY;
2561 *size = strlenW(ptr)/2;
2562 data = HeapAlloc(GetProcessHeap(),0,*size);
2564 byte[0] = '0';
2565 byte[1] = 'x';
2566 byte[4] = 0;
2567 count = 0;
2568 while (*ptr)
2570 byte[2]= *ptr;
2571 ptr++;
2572 byte[3]= *ptr;
2573 ptr++;
2574 data[count] = (BYTE)strtol(byte,NULL,0);
2575 count ++;
2577 HeapFree(GetProcessHeap(),0,deformated);
2579 TRACE("Data %li bytes(%i)\n",*size,count);
2581 else
2583 LPWSTR deformated;
2584 deformat_string(hPackage, &value[1], &deformated);
2586 *type=REG_DWORD;
2587 *size = sizeof(DWORD);
2588 data = HeapAlloc(GetProcessHeap(),0,*size);
2589 *(LPDWORD)data = atoiW(deformated);
2590 TRACE("DWORD %i\n",*data);
2592 HeapFree(GetProcessHeap(),0,deformated);
2595 else
2597 WCHAR *ptr;
2598 *type=REG_SZ;
2600 if (value[0]=='#')
2602 if (value[1]=='%')
2604 ptr = &value[2];
2605 *type=REG_EXPAND_SZ;
2607 else
2608 ptr = &value[1];
2610 else
2611 ptr=value;
2613 *size = deformat_string(hPackage, ptr,(LPWSTR*)&data);
2615 return data;
2618 static UINT ACTION_WriteRegistryValues(MSIHANDLE hPackage)
2620 UINT rc;
2621 MSIHANDLE view;
2622 MSIHANDLE row = 0;
2623 static const CHAR *ExecSeqQuery = "select * from Registry";
2624 MSIPACKAGE *package;
2626 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
2627 if (!package)
2628 return ERROR_INVALID_HANDLE;
2630 rc = MsiDatabaseOpenViewA(package->db, ExecSeqQuery, &view);
2632 if (rc != ERROR_SUCCESS)
2633 return rc;
2635 rc = MsiViewExecute(view, 0);
2636 if (rc != ERROR_SUCCESS)
2638 MsiViewClose(view);
2639 MsiCloseHandle(view);
2640 return rc;
2643 /* increment progress bar each time action data is sent */
2644 ui_progress(hPackage,1,1,1,0);
2646 while (1)
2648 static const WCHAR szHCR[] =
2649 {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T','\\',0};
2650 static const WCHAR szHCU[] =
2651 {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',0};
2652 static const WCHAR szHLM[] =
2653 {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',
2654 '\\',0};
2655 static const WCHAR szHU[] =
2656 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2658 WCHAR key[0x100];
2659 WCHAR name[0x100];
2660 LPWSTR value;
2661 LPSTR value_data = NULL;
2662 HKEY root_key, hkey;
2663 DWORD type,size;
2664 WCHAR component[0x100];
2665 INT component_index;
2666 MSIHANDLE uirow;
2667 WCHAR uikey[0x110];
2669 INT root;
2670 DWORD sz=0x100;
2672 rc = MsiViewFetch(view,&row);
2673 if (rc != ERROR_SUCCESS)
2675 rc = ERROR_SUCCESS;
2676 break;
2679 sz= 0x100;
2680 MsiRecordGetStringW(row,6,component,&sz);
2681 component_index = get_loaded_component(package,component);
2683 if (!package->components[component_index].Enabled ||
2684 !package->components[component_index].FeatureState)
2686 TRACE("Skipping write due to disabled component\n");
2687 MsiCloseHandle(row);
2688 continue;
2691 /* null values have special meanings during uninstalls and such */
2693 if(MsiRecordIsNull(row,5))
2695 MsiCloseHandle(row);
2696 continue;
2699 root = MsiRecordGetInteger(row,2);
2700 sz = 0x100;
2701 MsiRecordGetStringW(row,3,key,&sz);
2703 sz = 0x100;
2704 if (MsiRecordIsNull(row,4))
2705 name[0]=0;
2706 else
2707 MsiRecordGetStringW(row,4,name,&sz);
2709 /* get the root key */
2710 switch (root)
2712 case 0: root_key = HKEY_CLASSES_ROOT;
2713 strcpyW(uikey,szHCR); break;
2714 case 1: root_key = HKEY_CURRENT_USER;
2715 strcpyW(uikey,szHCU); break;
2716 case 2: root_key = HKEY_LOCAL_MACHINE;
2717 strcpyW(uikey,szHLM); break;
2718 case 3: root_key = HKEY_USERS;
2719 strcpyW(uikey,szHU); break;
2720 default:
2721 ERR("Unknown root %i\n",root);
2722 root_key=NULL;
2723 break;
2725 if (!root_key)
2727 MsiCloseHandle(row);
2728 continue;
2731 strcatW(uikey,key);
2732 if (RegCreateKeyW( root_key, key, &hkey))
2734 ERR("Could not create key %s\n",debugstr_w(key));
2735 MsiCloseHandle(row);
2736 continue;
2739 sz = 0;
2740 MsiRecordGetStringW(row,5,NULL,&sz);
2741 sz++;
2742 value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
2743 MsiRecordGetStringW(row,5,value,&sz);
2744 value_data = parse_value(hPackage, value, &type, &size);
2746 if (value_data)
2748 TRACE("Setting value %s\n",debugstr_w(name));
2749 RegSetValueExW(hkey, name, 0, type, value_data, size);
2751 uirow = MsiCreateRecord(3);
2752 MsiRecordSetStringW(uirow,2,name);
2753 MsiRecordSetStringW(uirow,1,uikey);
2755 if (type == REG_SZ)
2756 MsiRecordSetStringW(uirow,3,(LPWSTR)value_data);
2757 else
2758 MsiRecordSetStringW(uirow,3,value);
2760 ui_actiondata(hPackage,szWriteRegistryValues,uirow);
2761 ui_progress(hPackage,2,0,0,0);
2762 MsiCloseHandle(uirow);
2764 HeapFree(GetProcessHeap(),0,value_data);
2766 HeapFree(GetProcessHeap(),0,value);
2768 MsiCloseHandle(row);
2769 RegCloseKey(hkey);
2771 MsiViewClose(view);
2772 MsiCloseHandle(view);
2773 return rc;
2777 * This helper function should probably go alot of places
2779 * Thinking about this, maybe this should become yet another Bison file
2781 static DWORD deformat_string(MSIHANDLE hPackage, WCHAR* ptr,WCHAR** data)
2783 WCHAR* mark=NULL;
2784 DWORD size=0;
2785 DWORD chunk=0;
2786 WCHAR key[0x100];
2787 WCHAR value[0x100];
2788 DWORD sz;
2790 /* scan for special characters */
2791 if (!strchrW(ptr,'[') || (strchrW(ptr,'[') && !strchrW(ptr,']')))
2793 /* not formatted */
2794 size = (strlenW(ptr)+1) * sizeof(WCHAR);
2795 *data = HeapAlloc(GetProcessHeap(),0,size);
2796 strcpyW(*data,ptr);
2797 return size;
2800 /* formatted string located */
2801 mark = strchrW(ptr,'[');
2802 if (mark != ptr)
2804 INT cnt = (mark - ptr);
2805 TRACE("%i (%i) characters before marker\n",cnt,(mark-ptr));
2806 size = cnt * sizeof(WCHAR);
2807 size += sizeof(WCHAR);
2808 *data = HeapAlloc(GetProcessHeap(),0,size);
2809 strncpyW(*data,ptr,cnt);
2810 (*data)[cnt]=0;
2812 else
2814 size = sizeof(WCHAR);
2815 *data = HeapAlloc(GetProcessHeap(),0,size);
2816 (*data)[0]=0;
2818 mark++;
2819 strcpyW(key,mark);
2820 *strchrW(key,']')=0;
2821 mark = strchrW(mark,']');
2822 mark++;
2823 TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
2824 sz = 0x100;
2825 if (MsiGetPropertyW(hPackage, key, value,&sz) == ERROR_SUCCESS)
2827 LPWSTR newdata;
2828 chunk = (strlenW(value)+1) * sizeof(WCHAR);
2829 size+=chunk;
2830 newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
2831 *data = newdata;
2832 strcatW(*data,value);
2834 TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
2835 if (*mark!=0)
2837 LPWSTR newdata;
2838 chunk = (strlenW(mark)+1) * sizeof(WCHAR);
2839 size+=chunk;
2840 newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
2841 *data = newdata;
2842 strcatW(*data,mark);
2844 (*data)[strlenW(*data)]=0;
2845 TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
2847 /* recursively do this to clean up */
2848 mark = HeapAlloc(GetProcessHeap(),0,size);
2849 strcpyW(mark,*data);
2850 TRACE("String at this point %s\n",debugstr_w(mark));
2851 size = deformat_string(hPackage,mark,data);
2852 HeapFree(GetProcessHeap(),0,mark);
2853 return size;
2856 static UINT ACTION_InstallInitialize(MSIHANDLE hPackage)
2858 CHAR level[10000];
2859 INT install_level;
2860 DWORD sz;
2861 MSIPACKAGE *package;
2862 INT i,j;
2863 DWORD rc;
2864 LPWSTR override = NULL;
2865 static const WCHAR addlocal[]={'A','D','D','L','O','C','A','L',0};
2866 static const WCHAR all[]={'A','L','L',0};
2868 /* I do not know if this is where it should happen.. but */
2870 TRACE("Checking Install Level\n");
2872 sz = 10000;
2873 if (MsiGetPropertyA(hPackage,"INSTALLLEVEL",level,&sz)==ERROR_SUCCESS)
2874 install_level = atoi(level);
2875 else
2876 install_level = 1;
2878 sz = 0;
2879 rc = MsiGetPropertyA(hPackage,"ADDLOCAL",NULL,&sz);
2880 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2882 sz++;
2883 override = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
2884 MsiGetPropertyW(hPackage, addlocal,override,&sz);
2887 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
2888 if (!package)
2889 return ERROR_INVALID_HANDLE;
2892 * components FeatureState defaults to FALSE. the idea is we want to
2893 * enable the component is ANY feature that uses it is enabled to install
2895 for(i = 0; i < package->loaded_features; i++)
2897 BOOL feature_state= ((package->features[i].Level > 0) &&
2898 (package->features[i].Level <= install_level));
2900 if (override && (strcmpiW(override,all)==0 ||
2901 strstrW(override,package->features[i].Feature)))
2903 TRACE("Override of install level found\n");
2904 feature_state = TRUE;
2907 TRACE("Feature %s has a state of %i\n",
2908 debugstr_w(package->features[i].Feature), feature_state);
2909 for( j = 0; j < package->features[i].ComponentCount; j++)
2911 package->components[package->features[i].Components[j]].FeatureState
2912 |= feature_state;
2915 if (override != NULL)
2916 HeapFree(GetProcessHeap(),0,override);
2918 * so basically we ONLY want to install a component if its Enabled AND
2919 * FeatureState are both TRUE
2921 return ERROR_SUCCESS;
2924 static UINT ACTION_InstallValidate(MSIHANDLE hPackage)
2926 DWORD progress = 0;
2927 static const CHAR q1[]="SELECT * FROM Registry";
2928 UINT rc;
2929 MSIHANDLE view;
2930 MSIHANDLE row = 0;
2931 MSIHANDLE db;
2932 MSIPACKAGE* package;
2934 TRACE(" InstallValidate \n");
2936 db = MsiGetActiveDatabase(hPackage);
2937 rc = MsiDatabaseOpenViewA(db, q1, &view);
2938 rc = MsiViewExecute(view, 0);
2939 while (1)
2941 rc = MsiViewFetch(view,&row);
2942 if (rc != ERROR_SUCCESS)
2944 rc = ERROR_SUCCESS;
2945 break;
2947 progress +=1;
2949 MsiCloseHandle(row);
2951 MsiViewClose(view);
2952 MsiCloseHandle(view);
2953 MsiCloseHandle(db);
2955 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
2956 ui_progress(hPackage,0,progress+package->loaded_files,0,0);
2958 return ERROR_SUCCESS;
2961 static UINT ACTION_LaunchConditions(MSIHANDLE hPackage)
2963 UINT rc;
2964 MSIHANDLE view;
2965 MSIHANDLE row = 0;
2966 static const CHAR *ExecSeqQuery = "SELECT * from LaunchCondition";
2967 MSIHANDLE db;
2968 static const WCHAR title[]=
2969 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2971 TRACE("Checking launch conditions\n");
2973 db = MsiGetActiveDatabase(hPackage);
2974 rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
2975 MsiCloseHandle(db);
2977 if (rc != ERROR_SUCCESS)
2978 return rc;
2980 rc = MsiViewExecute(view, 0);
2981 if (rc != ERROR_SUCCESS)
2983 MsiViewClose(view);
2984 MsiCloseHandle(view);
2985 return rc;
2988 rc = ERROR_SUCCESS;
2989 while (rc == ERROR_SUCCESS)
2991 LPWSTR cond = NULL;
2992 LPWSTR message = NULL;
2993 DWORD sz;
2995 rc = MsiViewFetch(view,&row);
2996 if (rc != ERROR_SUCCESS)
2998 rc = ERROR_SUCCESS;
2999 break;
3002 sz = 0;
3003 MsiRecordGetStringW(row,1,NULL,&sz);
3004 sz++;
3005 cond = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
3006 MsiRecordGetStringW(row,1,cond,&sz);
3008 if (MsiEvaluateConditionW(hPackage,cond) != MSICONDITION_TRUE)
3010 sz = 0;
3011 MsiRecordGetStringW(row,2,NULL,&sz);
3012 sz++;
3013 message = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
3014 MsiRecordGetStringW(row,2,message,&sz);
3015 MessageBoxW(NULL,message,title,MB_OK);
3016 HeapFree(GetProcessHeap(),0,message);
3017 rc = ERROR_FUNCTION_FAILED;
3019 HeapFree(GetProcessHeap(),0,cond);
3020 MsiCloseHandle(row);
3022 MsiViewClose(view);
3023 MsiCloseHandle(view);
3024 return rc;
3027 static void resolve_keypath(MSIHANDLE hPackage, MSIPACKAGE* package, INT
3028 component_index, WCHAR *keypath)
3030 MSICOMPONENT* cmp = &package->components[component_index];
3032 if (cmp->KeyPath[0]==0)
3034 resolve_folder(hPackage,cmp->Directory,keypath,FALSE,FALSE,NULL);
3035 return;
3037 if ((cmp->Attributes & 0x4) || (cmp->Attributes & 0x20))
3039 FIXME("UNIMPLEMENTED keypath as Registry or ODBC Source\n");
3040 keypath[0]=0;
3042 else
3044 int j;
3045 j = get_loaded_file(package,cmp->KeyPath);
3047 if (j>=0)
3048 strcpyW(keypath,package->files[j].TargetPath);
3052 static UINT ACTION_ProcessComponents(MSIHANDLE hPackage)
3054 MSIPACKAGE* package;
3055 WCHAR productcode[0x100];
3056 WCHAR squished_pc[0x100];
3057 WCHAR squished_cc[0x100];
3058 DWORD sz;
3059 UINT rc;
3060 INT i;
3061 HKEY hkey=0,hkey2=0,hkey3=0;
3062 static const WCHAR szProductCode[]=
3063 {'P','r','o','d','u','c','t','C','o','d','e',0};
3064 static const WCHAR szInstaller[] = {
3065 'S','o','f','t','w','a','r','e','\\',
3066 'M','i','c','r','o','s','o','f','t','\\',
3067 'W','i','n','d','o','w','s','\\',
3068 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3069 'I','n','s','t','a','l','l','e','r',0 };
3070 static const WCHAR szFeatures[] = {
3071 'F','e','a','t','u','r','e','s',0 };
3072 static const WCHAR szComponents[] = {
3073 'C','o','m','p','o','n','e','n','t','s',0 };
3075 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
3076 if (!package)
3077 return ERROR_INVALID_HANDLE;
3079 /* writes the Component and Features values to the registry */
3080 sz = 0x100;
3081 rc = MsiGetPropertyW(hPackage,szProductCode,productcode,&sz);
3083 if (rc != ERROR_SUCCESS)
3084 return ERROR_SUCCESS;
3086 squash_guid(productcode,squished_pc);
3087 rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller,&hkey);
3088 if (rc != ERROR_SUCCESS)
3089 goto end;
3091 rc = RegCreateKeyW(hkey,szFeatures,&hkey2);
3092 if (rc != ERROR_SUCCESS)
3093 goto end;
3095 rc = RegCreateKeyW(hkey2,squished_pc,&hkey3);
3096 if (rc != ERROR_SUCCESS)
3097 goto end;
3099 /* I have no idea what goes in here */
3100 for (i = 0; i < package->loaded_features; i++)
3101 RegSetValueExW(hkey3,package->features[i].Feature,0,REG_SZ,NULL,0);
3103 RegCloseKey(hkey3);
3104 RegCloseKey(hkey2);
3106 rc = RegCreateKeyW(hkey,szComponents,&hkey2);
3107 if (rc != ERROR_SUCCESS)
3108 goto end;
3110 for (i = 0; i < package->loaded_components; i++)
3112 if (package->components[i].ComponentId[0]!=0)
3114 WCHAR keypath[0x1000];
3115 MSIHANDLE uirow;
3117 squash_guid(package->components[i].ComponentId,squished_cc);
3118 rc = RegCreateKeyW(hkey2,squished_cc,&hkey3);
3119 if (rc != ERROR_SUCCESS)
3120 continue;
3122 resolve_keypath(hPackage,package,i,keypath);
3124 RegSetValueExW(hkey3,squished_pc,0,REG_SZ,(LPVOID)keypath,
3125 (strlenW(keypath)+1)*sizeof(WCHAR));
3126 RegCloseKey(hkey3);
3128 /* UI stuff */
3129 uirow = MsiCreateRecord(3);
3130 MsiRecordSetStringW(uirow,1,productcode);
3131 MsiRecordSetStringW(uirow,2,package->components[i].ComponentId);
3132 MsiRecordSetStringW(uirow,3,keypath);
3133 ui_actiondata(hPackage,szProcessComponents,uirow);
3134 MsiCloseHandle(uirow);
3137 end:
3138 RegCloseKey(hkey2);
3139 RegCloseKey(hkey);
3140 return rc;
3143 static UINT ACTION_RegisterTypeLibraries(MSIHANDLE hPackage)
3146 * ok this is a bit confusting.. I am given a _Component key and i believe
3147 * that the file that is being registered as a type library is the "key file
3148 * of that component" which i interpert to mean "The file in the KeyPath of
3149 * that component"
3151 UINT rc;
3152 MSIHANDLE view;
3153 MSIHANDLE row = 0;
3154 static const CHAR *Query = "SELECT * from TypeLib";
3155 MSIPACKAGE* package;
3156 ITypeLib *ptLib;
3157 HRESULT res;
3159 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
3160 if (!package)
3161 return ERROR_INVALID_HANDLE;
3163 rc = MsiDatabaseOpenViewA(package->db, Query, &view);
3165 if (rc != ERROR_SUCCESS)
3166 return rc;
3168 rc = MsiViewExecute(view, 0);
3169 if (rc != ERROR_SUCCESS)
3171 MsiViewClose(view);
3172 MsiCloseHandle(view);
3173 return rc;
3176 while (1)
3178 WCHAR component[0x100];
3179 DWORD sz;
3180 INT index;
3182 rc = MsiViewFetch(view,&row);
3183 if (rc != ERROR_SUCCESS)
3185 rc = ERROR_SUCCESS;
3186 break;
3189 sz = 0x100;
3190 MsiRecordGetStringW(row,3,component,&sz);
3192 index = get_loaded_component(package,component);
3193 if (index < 0)
3195 MsiCloseHandle(row);
3196 continue;
3199 if (!package->components[index].Enabled ||
3200 !package->components[index].FeatureState)
3202 TRACE("Skipping typelib reg due to disabled component\n");
3203 MsiCloseHandle(row);
3204 continue;
3207 index = get_loaded_file(package,package->components[index].KeyPath);
3209 if (index < 0)
3211 MsiCloseHandle(row);
3212 continue;
3215 res = LoadTypeLib(package->files[index].TargetPath,&ptLib);
3216 if (SUCCEEDED(res))
3218 WCHAR help[MAX_PATH];
3219 WCHAR helpid[0x100];
3221 sz = 0x100;
3222 MsiRecordGetStringW(row,6,helpid,&sz);
3224 resolve_folder(hPackage,helpid,help,FALSE,FALSE,NULL);
3226 res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help);
3227 if (!SUCCEEDED(res))
3228 ERR("Failed to register type library %s\n",
3229 debugstr_w(package->files[index].TargetPath));
3230 else
3232 /* yes the row has more fields than i need, but #1 is
3233 correct and the only one i need. why make a new row */
3235 ui_actiondata(hPackage,szRegisterTypeLibraries,row);
3237 TRACE("Registered %s\n",
3238 debugstr_w(package->files[index].TargetPath));
3241 if (ptLib)
3242 ITypeLib_Release(ptLib);
3244 else
3245 ERR("Failed to load type library %s\n",
3246 debugstr_w(package->files[index].TargetPath));
3248 MsiCloseHandle(row);
3250 MsiViewClose(view);
3251 MsiCloseHandle(view);
3252 return rc;
3256 static UINT register_appid(MSIHANDLE hPackage, LPCWSTR clsid, LPCWSTR app )
3258 static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
3259 UINT rc;
3260 MSIHANDLE view;
3261 MSIHANDLE row = 0;
3262 static const WCHAR ExecSeqQuery[] =
3263 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'
3264 ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};
3265 WCHAR Query[0x1000];
3266 MSIPACKAGE* package;
3267 HKEY hkey2,hkey3;
3268 LPWSTR buffer=0;
3269 DWORD sz;
3271 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
3272 if (!package)
3273 return ERROR_INVALID_HANDLE;
3276 sprintfW(Query,ExecSeqQuery,clsid);
3278 rc = MsiDatabaseOpenViewW(package->db, Query, &view);
3279 if (rc != ERROR_SUCCESS)
3280 return rc;
3282 rc = MsiViewExecute(view, 0);
3283 if (rc != ERROR_SUCCESS)
3285 MsiViewClose(view);
3286 MsiCloseHandle(view);
3287 return rc;
3290 RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
3291 RegCreateKeyW(hkey2,clsid,&hkey3);
3292 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
3293 (strlenW(app)+1)*sizeof(WCHAR));
3295 MsiViewFetch(view,&row);
3297 if (!MsiRecordIsNull(row,2))
3299 LPWSTR deformated=0;
3300 UINT size;
3301 static const WCHAR szRemoteServerName[] =
3302 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
3303 sz = 0;
3304 MsiRecordGetStringW(row,2,NULL,&sz);
3305 sz++;
3306 buffer = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
3307 MsiRecordGetStringW(row,2,buffer,&sz);
3308 size = deformat_string(hPackage,buffer,&deformated);
3309 RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated,
3310 size);
3311 HeapFree(GetProcessHeap(),0,deformated);
3312 HeapFree(GetProcessHeap(),0,buffer);
3315 if (!MsiRecordIsNull(row,3))
3317 static const WCHAR szLocalService[] =
3318 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
3319 UINT size;
3320 sz = 0;
3321 MsiRecordGetStringW(row,3,NULL,&sz);
3322 sz++;
3323 size = sz * sizeof(WCHAR);
3324 buffer = HeapAlloc(GetProcessHeap(),0,size);
3325 MsiRecordGetStringW(row,3,buffer,&sz);
3326 RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size);
3327 HeapFree(GetProcessHeap(),0,buffer);
3330 if (!MsiRecordIsNull(row,4))
3332 static const WCHAR szService[] =
3333 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
3334 UINT size;
3335 sz = 0;
3336 MsiRecordGetStringW(row,4,NULL,&sz);
3337 sz++;
3338 size = sz * sizeof(WCHAR);
3339 buffer = HeapAlloc(GetProcessHeap(),0,size);
3340 MsiRecordGetStringW(row,4,buffer,&sz);
3341 RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size);
3342 HeapFree(GetProcessHeap(),0,buffer);
3345 if (!MsiRecordIsNull(row,5))
3347 static const WCHAR szDLL[] =
3348 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
3349 UINT size;
3350 sz = 0;
3351 MsiRecordGetStringW(row,5,NULL,&sz);
3352 sz++;
3353 size = sz * sizeof(WCHAR);
3354 buffer = HeapAlloc(GetProcessHeap(),0,size);
3355 MsiRecordGetStringW(row,5,buffer,&sz);
3356 RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size);
3357 HeapFree(GetProcessHeap(),0,buffer);
3360 if (!MsiRecordIsNull(row,6))
3362 static const WCHAR szActivate[] =
3363 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
3364 static const WCHAR szY[] = {'Y',0};
3366 if (MsiRecordGetInteger(row,6))
3367 RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
3370 if (!MsiRecordIsNull(row,7))
3372 static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
3373 static const WCHAR szUser[] =
3374 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
3376 if (MsiRecordGetInteger(row,7))
3377 RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34);
3380 MsiCloseHandle(row);
3381 MsiViewClose(view);
3382 MsiCloseHandle(view);
3383 RegCloseKey(hkey3);
3384 RegCloseKey(hkey2);
3385 return rc;
3388 static UINT ACTION_RegisterClassInfo(MSIHANDLE hPackage)
3391 * again i am assuming the words, "Whose key file respesents" when refering
3392 * to a Component as to meanin that Components KeyPath file
3394 * Also there is a very strong connection between ClassInfo and ProgID
3395 * that i am mostly glossing over.
3396 * What would be more proper is to load the ClassInfo and the ProgID info
3397 * into memory data structures and then be able to enable and disable them
3398 * based on component.
3401 UINT rc;
3402 MSIHANDLE view;
3403 MSIHANDLE row = 0;
3404 static const CHAR *ExecSeqQuery = "SELECT * from Class";
3405 MSIPACKAGE* package;
3406 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
3407 static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
3408 static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
3409 HKEY hkey,hkey2,hkey3;
3411 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
3412 if (!package)
3413 return ERROR_INVALID_HANDLE;
3415 rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
3416 if (rc != ERROR_SUCCESS)
3417 return ERROR_FUNCTION_FAILED;
3419 rc = MsiDatabaseOpenViewA(package->db, ExecSeqQuery, &view);
3421 if (rc != ERROR_SUCCESS)
3422 goto end;
3424 rc = MsiViewExecute(view, 0);
3425 if (rc != ERROR_SUCCESS)
3427 MsiViewClose(view);
3428 MsiCloseHandle(view);
3429 goto end;
3432 while (1)
3434 WCHAR clsid[0x100];
3435 WCHAR buffer[0x100];
3436 WCHAR desc[0x100];
3437 DWORD sz;
3438 INT index;
3440 rc = MsiViewFetch(view,&row);
3441 if (rc != ERROR_SUCCESS)
3443 rc = ERROR_SUCCESS;
3444 break;
3447 sz=0x100;
3448 MsiRecordGetStringW(row,3,buffer,&sz);
3450 index = get_loaded_component(package,buffer);
3452 if (index < 0)
3454 MsiCloseHandle(row);
3455 continue;
3458 if (!package->components[index].Enabled ||
3459 !package->components[index].FeatureState)
3461 TRACE("Skipping class reg due to disabled component\n");
3462 MsiCloseHandle(row);
3463 continue;
3466 sz=0x100;
3467 MsiRecordGetStringW(row,1,clsid,&sz);
3468 RegCreateKeyW(hkey,clsid,&hkey2);
3470 if (!MsiRecordIsNull(row,5))
3472 sz=0x100;
3473 MsiRecordGetStringW(row,5,desc,&sz);
3475 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc,
3476 (strlenW(desc)+1)*sizeof(WCHAR));
3478 else
3479 desc[0]=0;
3481 sz=0x100;
3482 MsiRecordGetStringW(row,2,buffer,&sz);
3484 RegCreateKeyW(hkey2,buffer,&hkey3);
3486 index = get_loaded_file(package,package->components[index].KeyPath);
3487 RegSetValueExW(hkey3,NULL,0,REG_SZ,
3488 (LPVOID)package->files[index].TargetPath,
3489 (strlenW(package->files[index].TargetPath)+1)
3490 *sizeof(WCHAR));
3492 RegCloseKey(hkey3);
3494 if (!MsiRecordIsNull(row,4))
3496 sz=0x100;
3497 MsiRecordGetStringW(row,4,buffer,&sz);
3499 RegCreateKeyW(hkey2,szProgID,&hkey3);
3501 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer,
3502 (strlenW(buffer)+1)*sizeof(WCHAR));
3504 RegCloseKey(hkey3);
3507 if (!MsiRecordIsNull(row,6))
3509 sz=0x100;
3510 MsiRecordGetStringW(row,6,buffer,&sz);
3512 RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer,
3513 (strlenW(buffer)+1)*sizeof(WCHAR));
3515 register_appid(hPackage,buffer,desc);
3518 RegCloseKey(hkey2);
3520 FIXME("Process the rest of the fields >7\n");
3522 ui_actiondata(hPackage,szRegisterClassInfo,row);
3524 MsiCloseHandle(row);
3526 MsiViewClose(view);
3527 MsiCloseHandle(view);
3529 end:
3530 RegCloseKey(hkey);
3531 return rc;
3534 static UINT register_progid_base(MSIHANDLE row, LPWSTR clsid)
3536 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
3537 HKEY hkey,hkey2;
3538 WCHAR buffer[0x1000];
3539 DWORD sz;
3542 sz = 0x1000;
3543 MsiRecordGetStringW(row,1,buffer,&sz);
3544 RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
3546 if (!MsiRecordIsNull(row,4))
3548 sz = 0x1000;
3549 MsiRecordGetStringW(row,4,buffer,&sz);
3550 RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
3551 sizeof(WCHAR));
3554 if (!MsiRecordIsNull(row,3))
3556 sz = 0x1000;
3558 MsiRecordGetStringW(row,3,buffer,&sz);
3559 RegCreateKeyW(hkey,szCLSID,&hkey2);
3560 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
3561 sizeof(WCHAR));
3563 if (clsid)
3564 strcpyW(clsid,buffer);
3566 RegCloseKey(hkey2);
3568 else
3570 FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
3571 return ERROR_FUNCTION_FAILED;
3573 if (!MsiRecordIsNull(row,5))
3574 FIXME ("UNHANDLED icon in Progid\n");
3575 return ERROR_SUCCESS;
3578 static UINT register_progid(MSIHANDLE hPackage, MSIHANDLE row, LPWSTR clsid);
3580 static UINT register_parent_progid(MSIHANDLE hPackage, LPCWSTR parent,
3581 LPWSTR clsid)
3583 UINT rc;
3584 MSIHANDLE view;
3585 MSIHANDLE row = 0;
3586 static const WCHAR Query_t[] =
3587 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'
3588 ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'
3589 ,'%','s','`',0};
3590 WCHAR Query[0x1000];
3591 MSIPACKAGE* package;
3593 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
3594 if (!package)
3595 return ERROR_INVALID_HANDLE;
3597 sprintfW(Query,Query_t,parent);
3599 rc = MsiDatabaseOpenViewW(package->db, Query, &view);
3601 if (rc != ERROR_SUCCESS)
3602 return rc;
3604 rc = MsiViewExecute(view, 0);
3605 if (rc != ERROR_SUCCESS)
3607 MsiViewClose(view);
3608 MsiCloseHandle(view);
3609 return rc;
3612 rc = MsiViewFetch(view,&row);
3613 if (rc != ERROR_SUCCESS)
3615 MsiViewClose(view);
3616 MsiCloseHandle(view);
3617 return rc;
3620 register_progid(hPackage,row,clsid);
3622 MsiCloseHandle(row);
3623 MsiViewClose(view);
3624 MsiCloseHandle(view);
3625 return rc;
3628 static UINT register_progid(MSIHANDLE hPackage, MSIHANDLE row, LPWSTR clsid)
3630 UINT rc = ERROR_SUCCESS;
3632 if (MsiRecordIsNull(row,2))
3633 rc = register_progid_base(row,clsid);
3634 else
3636 WCHAR buffer[0x1000];
3637 DWORD sz;
3638 HKEY hkey,hkey2;
3639 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
3641 sz = 0x1000;
3642 MsiRecordGetStringW(row,2,buffer,&sz);
3643 rc = register_parent_progid(hPackage,buffer,clsid);
3645 sz = 0x1000;
3646 MsiRecordGetStringW(row,1,buffer,&sz);
3647 RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
3648 /* clasid is same as parent */
3649 RegCreateKeyW(hkey,szCLSID,&hkey2);
3650 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
3651 sizeof(WCHAR));
3653 RegCloseKey(hkey2);
3654 if (!MsiRecordIsNull(row,4))
3656 sz = 0x1000;
3657 MsiRecordGetStringW(row,4,buffer,&sz);
3658 RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer,
3659 (strlenW(buffer)+1) * sizeof(WCHAR));
3662 if (!MsiRecordIsNull(row,5))
3663 FIXME ("UNHANDLED icon in Progid\n");
3665 RegCloseKey(hkey);
3667 return rc;
3670 static UINT ACTION_RegisterProgIdInfo(MSIHANDLE hPackage)
3673 * Sigh, here i am just brute force registering all progid
3674 * this needs to be linked to the Classes that have been registerd
3675 * but the easiest way to do that is to load all these stuff into
3676 * memory for easy checking.
3678 * gives me something to continue to work toward
3680 UINT rc;
3681 MSIHANDLE view;
3682 MSIHANDLE row = 0;
3683 static const CHAR *Query = "SELECT * FROM ProgId";
3684 MSIPACKAGE* package;
3686 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
3687 if (!package)
3688 return ERROR_INVALID_HANDLE;
3690 rc = MsiDatabaseOpenViewA(package->db, Query, &view);
3692 if (rc != ERROR_SUCCESS)
3693 return rc;
3695 rc = MsiViewExecute(view, 0);
3696 if (rc != ERROR_SUCCESS)
3698 MsiViewClose(view);
3699 MsiCloseHandle(view);
3700 return rc;
3703 while (1)
3705 WCHAR clsid[0x1000];
3707 rc = MsiViewFetch(view,&row);
3708 if (rc != ERROR_SUCCESS)
3710 rc = ERROR_SUCCESS;
3711 break;
3714 register_progid(hPackage,row,clsid);
3716 MsiCloseHandle(row);
3718 MsiViewClose(view);
3719 MsiCloseHandle(view);
3720 return rc;
3723 /* Msi functions that seem approperate here */
3724 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
3726 LPWSTR szwAction;
3727 UINT len,rc;
3729 TRACE(" exteral attempt at action %s\n",szAction);
3731 if (!szAction)
3732 return ERROR_FUNCTION_FAILED;
3733 if (hInstall == 0)
3734 return ERROR_FUNCTION_FAILED;
3736 len = MultiByteToWideChar( CP_ACP, 0, szAction, -1, NULL, 0);
3737 szwAction = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3739 if (!szwAction)
3740 return ERROR_FUNCTION_FAILED;
3742 MultiByteToWideChar( CP_ACP, 0, szAction, -1, szwAction, len);
3744 rc = MsiDoActionW(hInstall, szwAction);
3745 HeapFree(GetProcessHeap(),0,szwAction);
3746 return rc;
3749 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
3751 TRACE(" exteral attempt at action %s \n",debugstr_w(szAction));
3752 return ACTION_PerformAction(hInstall,szAction);
3755 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
3756 LPSTR szPathBuf, DWORD* pcchPathBuf)
3758 LPWSTR szwFolder;
3759 LPWSTR szwPathBuf;
3760 UINT len,rc;
3762 TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
3764 if (!szFolder)
3765 return ERROR_FUNCTION_FAILED;
3766 if (hInstall == 0)
3767 return ERROR_FUNCTION_FAILED;
3769 len = MultiByteToWideChar( CP_ACP, 0, szFolder, -1, NULL, 0);
3770 szwFolder= HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3772 if (!szwFolder)
3773 return ERROR_FUNCTION_FAILED;
3775 szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
3777 MultiByteToWideChar( CP_ACP, 0, szFolder, -1, szwFolder, len);
3779 rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
3781 WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
3782 *pcchPathBuf, NULL, NULL );
3784 HeapFree(GetProcessHeap(),0,szwFolder);
3785 HeapFree(GetProcessHeap(),0,szwPathBuf);
3787 return rc;
3790 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
3791 szPathBuf, DWORD* pcchPathBuf)
3793 WCHAR path[MAX_PATH];
3794 UINT rc;
3796 TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
3798 rc = resolve_folder(hInstall, szFolder, path, FALSE, FALSE, NULL);
3800 if (rc == ERROR_SUCCESS && strlenW(path) > *pcchPathBuf)
3802 *pcchPathBuf = strlenW(path)+1;
3803 return ERROR_MORE_DATA;
3805 else if (rc == ERROR_SUCCESS)
3807 *pcchPathBuf = strlenW(path)+1;
3808 strcpyW(szPathBuf,path);
3809 TRACE("Returning Path %s\n",debugstr_w(path));
3812 return rc;
3816 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder,
3817 LPSTR szPathBuf, DWORD* pcchPathBuf)
3819 LPWSTR szwFolder;
3820 LPWSTR szwPathBuf;
3821 UINT len,rc;
3823 TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
3825 if (!szFolder)
3826 return ERROR_FUNCTION_FAILED;
3827 if (hInstall == 0)
3828 return ERROR_FUNCTION_FAILED;
3830 len = MultiByteToWideChar( CP_ACP, 0, szFolder, -1, NULL, 0);
3831 szwFolder= HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3833 if (!szwFolder)
3834 return ERROR_FUNCTION_FAILED;
3836 szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
3838 MultiByteToWideChar( CP_ACP, 0, szFolder, -1, szwFolder, len);
3840 rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
3842 WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
3843 *pcchPathBuf, NULL, NULL );
3845 HeapFree(GetProcessHeap(),0,szwFolder);
3846 HeapFree(GetProcessHeap(),0,szwPathBuf);
3848 return rc;
3851 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
3852 szPathBuf, DWORD* pcchPathBuf)
3854 WCHAR path[MAX_PATH];
3855 UINT rc;
3857 TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
3858 rc = resolve_folder(hInstall, szFolder, path, TRUE, FALSE, NULL);
3860 if (rc == ERROR_SUCCESS && strlenW(path) > *pcchPathBuf)
3862 *pcchPathBuf = strlenW(path)+1;
3863 return ERROR_MORE_DATA;
3865 else if (rc == ERROR_SUCCESS)
3867 *pcchPathBuf = strlenW(path)+1;
3868 strcpyW(szPathBuf,path);
3869 TRACE("Returning Path %s\n",debugstr_w(path));
3872 return rc;
3876 UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder,
3877 LPCSTR szFolderPath)
3879 LPWSTR szwFolder;
3880 LPWSTR szwFolderPath;
3881 UINT rc,len;
3883 if (!szFolder)
3884 return ERROR_FUNCTION_FAILED;
3885 if (hInstall == 0)
3886 return ERROR_FUNCTION_FAILED;
3888 len = MultiByteToWideChar( CP_ACP, 0, szFolder, -1, NULL, 0);
3889 szwFolder= HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3891 if (!szwFolder)
3892 return ERROR_FUNCTION_FAILED;
3894 MultiByteToWideChar( CP_ACP, 0, szFolder, -1, szwFolder, len);
3896 len = MultiByteToWideChar( CP_ACP, 0, szFolderPath, -1, NULL, 0);
3897 szwFolderPath= HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3899 if (!szwFolderPath)
3901 HeapFree(GetProcessHeap(),0,szwFolder);
3902 return ERROR_FUNCTION_FAILED;
3905 MultiByteToWideChar( CP_ACP, 0, szFolderPath, -1, szwFolderPath, len);
3907 rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
3909 HeapFree(GetProcessHeap(),0,szwFolder);
3910 HeapFree(GetProcessHeap(),0,szwFolderPath);
3912 return rc;
3915 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
3916 LPCWSTR szFolderPath)
3918 MSIPACKAGE *package;
3919 INT i;
3920 WCHAR path[MAX_PATH];
3921 MSIFOLDER *folder;
3923 TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
3925 if (szFolderPath[0]==0)
3926 return ERROR_FUNCTION_FAILED;
3928 if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)
3929 return ERROR_FUNCTION_FAILED;
3931 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
3933 if (package==NULL)
3934 return ERROR_INVALID_HANDLE;
3936 resolve_folder(hInstall,szFolder,path,FALSE,FALSE,&folder);
3938 if (!folder)
3939 return ERROR_INVALID_PARAMETER;
3941 strcpyW(folder->Property,szFolderPath);
3943 for (i = 0; i < package->loaded_folders; i++)
3944 package->folders[i].ResolvedTarget[0]=0;
3946 for (i = 0; i < package->loaded_folders; i++)
3947 resolve_folder(hInstall, package->folders[i].Directory, path, FALSE,
3948 TRUE, NULL);
3950 return ERROR_SUCCESS;
3953 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, DWORD iRunMode)
3955 FIXME("STUB (%li)\n",iRunMode);
3956 return FALSE;
3959 #if 0
3960 static UINT ACTION_Template(MSIHANDLE hPackage)
3962 UINT rc;
3963 MSIHANDLE view;
3964 MSIHANDLE row = 0;
3965 static const CHAR *ExecSeqQuery;
3966 MSIPACKAGE* package;
3968 package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
3969 if (!package)
3970 return ERROR_INVALID_HANDLE;
3972 rc = MsiDatabaseOpenViewA(package->db, ExecSeqQuery, &view);
3974 if (rc != ERROR_SUCCESS)
3975 return rc;
3977 rc = MsiViewExecute(view, 0);
3978 if (rc != ERROR_SUCCESS)
3980 MsiViewClose(view);
3981 MsiCloseHandle(view);
3982 return rc;
3985 while (1)
3987 rc = MsiViewFetch(view,&row);
3988 if (rc != ERROR_SUCCESS)
3990 rc = ERROR_SUCCESS;
3991 break;
3994 MsiCloseHandle(row);
3996 MsiViewClose(view);
3997 MsiCloseHandle(view);
3998 return rc;
4000 #endif