Authors: Mike McCormack <mike@codeweavers.com>, Aric Stewart <aric@codeweavers.com>
[wine/multimedia.git] / dlls / msi / action.c
blobd5b93a6c20f108c8c14d36bc203846fa8c02aef2
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 BOOL Enabled;
65 INT ComponentCount;
66 INT Components[1024]; /* yes hardcoded limit.... I am bad */
67 INT Cost;
68 } MSIFEATURE;
70 typedef struct tagMSICOMPONENT
72 WCHAR Component[96];
73 WCHAR ComponentId[96];
74 WCHAR Directory[96];
75 INT Attributes;
76 WCHAR Condition[0x100];
77 WCHAR KeyPath[96];
79 INSTALLSTATE State;
80 BOOL FeatureState;
81 BOOL Enabled;
82 INT Cost;
83 } MSICOMPONENT;
85 typedef struct tagMSIFOLDER
87 WCHAR Directory[96];
88 WCHAR TargetDefault[96];
89 WCHAR SourceDefault[96];
91 WCHAR ResolvedTarget[MAX_PATH];
92 WCHAR ResolvedSource[MAX_PATH];
93 WCHAR Property[MAX_PATH]; /* initially set property */
94 INT ParentIndex;
95 INT State;
96 /* 0 = uninitialized */
97 /* 1 = existing */
98 /* 2 = created remove if empty */
99 /* 3 = created persist if empty */
100 INT Cost;
101 INT Space;
102 }MSIFOLDER;
104 typedef struct tagMSIFILE
106 WCHAR File[72];
107 INT ComponentIndex;
108 WCHAR FileName[MAX_PATH];
109 INT FileSize;
110 WCHAR Version[72];
111 WCHAR Language[20];
112 INT Attributes;
113 INT Sequence;
115 INT State;
116 /* 0 = uninitialize */
117 /* 1 = not present */
118 /* 2 = present but replace */
119 /* 3 = present do not replace */
120 /* 4 = Installed */
121 WCHAR SourcePath[MAX_PATH];
122 WCHAR TargetPath[MAX_PATH];
123 BOOL Temporary;
124 }MSIFILE;
127 * Prototypes
129 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
130 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
132 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action);
134 static UINT ACTION_LaunchConditions(MSIPACKAGE *package);
135 static UINT ACTION_CostInitialize(MSIPACKAGE *package);
136 static UINT ACTION_CreateFolders(MSIPACKAGE *package);
137 static UINT ACTION_CostFinalize(MSIPACKAGE *package);
138 static UINT ACTION_FileCost(MSIPACKAGE *package);
139 static UINT ACTION_InstallFiles(MSIPACKAGE *package);
140 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
141 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package);
142 static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action);
143 static UINT ACTION_InstallInitialize(MSIPACKAGE *package);
144 static UINT ACTION_InstallValidate(MSIPACKAGE *package);
145 static UINT ACTION_ProcessComponents(MSIPACKAGE *package);
146 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package);
147 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
148 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
149 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package);
150 static UINT ACTION_PublishProduct(MSIPACKAGE *package);
152 static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source,
153 const LPWSTR target, const INT type);
154 static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source,
155 const LPWSTR target, const INT type);
157 static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data);
158 static UINT resolve_folder(MSIPACKAGE *package, LPCWSTR name, LPWSTR path,
159 BOOL source, BOOL set_prop, MSIFOLDER **folder);
161 static UINT track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path);
164 * consts and values used
166 static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
167 static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
168 static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
169 static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
170 static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
171 static const WCHAR c_collen[] = {'C',':','\\',0};
173 static const WCHAR cszlsb[]={'[',0};
174 static const WCHAR cszrsb[]={']',0};
175 static const WCHAR cszbs[]={'\\',0};
177 const static WCHAR szCreateFolders[] =
178 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
179 const static WCHAR szCostFinalize[] =
180 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
181 const static WCHAR szInstallFiles[] =
182 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
183 const static WCHAR szDuplicateFiles[] =
184 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
185 const static WCHAR szWriteRegistryValues[] =
186 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
187 const static WCHAR szCostInitialize[] =
188 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
189 const static WCHAR szFileCost[] = {'F','i','l','e','C','o','s','t',0};
190 const static WCHAR szInstallInitialize[] =
191 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
192 const static WCHAR szInstallValidate[] =
193 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
194 const static WCHAR szLaunchConditions[] =
195 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
196 const static WCHAR szProcessComponents[] =
197 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
198 const static WCHAR szRegisterTypeLibraries[] =
199 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r',
200 'i','e','s',0};
201 const static WCHAR szRegisterClassInfo[] =
202 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
203 const static WCHAR szRegisterProgIdInfo[] =
204 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
205 const static WCHAR szCreateShortcuts[] =
206 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
207 const static WCHAR szPublishProduct[] =
208 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
210 /********************************************************
211 * helper functions to get around current HACKS and such
212 ********************************************************/
213 inline static void reduce_to_longfilename(WCHAR* filename)
215 if (strchrW(filename,'|'))
217 WCHAR newname[MAX_PATH];
218 strcpyW(newname,strchrW(filename,'|')+1);
219 strcpyW(filename,newname);
223 inline static char *strdupWtoA( const WCHAR *str )
225 char *ret = NULL;
226 if (str)
228 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL
230 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
231 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
233 return ret;
236 inline static WCHAR *strdupAtoW( const char *str )
238 WCHAR *ret = NULL;
239 if (str)
241 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
242 if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
243 MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
245 return ret;
248 inline static WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
250 UINT rc;
251 DWORD sz;
252 LPWSTR ret;
254 sz = 0;
255 rc = MSI_RecordGetStringW(row,index,NULL,&sz);
256 if (sz <= 0)
257 return NULL;
259 sz ++;
260 ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
261 rc = MSI_RecordGetStringW(row,index,ret,&sz);
262 return ret;
265 inline static int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
267 INT rc = -1;
268 INT i;
270 for (i = 0; i < package->loaded_components; i++)
272 if (strcmpW(Component,package->components[i].Component)==0)
274 rc = i;
275 break;
278 return rc;
281 inline static int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
283 INT rc = -1;
284 INT i;
286 for (i = 0; i < package->loaded_features; i++)
288 if (strcmpW(Feature,package->features[i].Feature)==0)
290 rc = i;
291 break;
294 return rc;
297 inline static int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
299 INT rc = -1;
300 INT i;
302 for (i = 0; i < package->loaded_files; i++)
304 if (strcmpW(file,package->files[i].File)==0)
306 rc = i;
307 break;
310 return rc;
313 static UINT track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
315 int i;
316 int index;
318 if (!package)
319 return -2;
321 for (i=0; i < package->loaded_files; i++)
322 if (strcmpW(package->files[i].File,name)==0)
323 return -1;
325 index = package->loaded_files;
326 package->loaded_files++;
327 if (package->loaded_files== 1)
328 package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
329 else
330 package->files = HeapReAlloc(GetProcessHeap(),0,
331 package->files , package->loaded_files * sizeof(MSIFILE));
333 memset(&package->files[index],0,sizeof(MSIFILE));
335 strcpyW(package->files[index].File,name);
336 strcpyW(package->files[index].TargetPath,path);
337 package->files[index].Temporary = TRUE;
339 TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));
341 return 0;
344 void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package)
346 int i;
348 if (!package)
349 return;
351 for (i = 0; i < package->loaded_files; i++)
353 if (package->files[i].Temporary)
354 DeleteFileW(package->files[i].TargetPath);
359 static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )
361 MSIRECORD * row;
363 row = MSI_CreateRecord(4);
364 MSI_RecordSetInteger(row,1,a);
365 MSI_RecordSetInteger(row,2,b);
366 MSI_RecordSetInteger(row,3,c);
367 MSI_RecordSetInteger(row,4,d);
368 MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);
369 msiobj_release(&row->hdr);
372 static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
374 static const WCHAR Query_t[] =
375 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
376 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
377 ' ','\'','%','s','\'',0};
378 WCHAR message[1024];
379 UINT rc;
380 MSIQUERY * view;
381 MSIRECORD * row = 0;
382 static WCHAR *ActionFormat=NULL;
383 static WCHAR LastAction[0x100] = {0};
384 WCHAR Query[1024];
385 LPWSTR ptr;
387 if (strcmpW(LastAction,action)!=0)
389 sprintfW(Query,Query_t,action);
390 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
391 if (rc != ERROR_SUCCESS)
392 return;
393 rc = MSI_ViewExecute(view, 0);
394 if (rc != ERROR_SUCCESS)
396 MSI_ViewClose(view);
397 return;
399 rc = MSI_ViewFetch(view,&row);
400 if (rc != ERROR_SUCCESS)
402 MSI_ViewClose(view);
403 return;
406 if (MSI_RecordIsNull(row,3))
408 msiobj_release(&row->hdr);
409 MSI_ViewClose(view);
410 msiobj_release(&view->hdr);
411 return;
414 if (ActionFormat)
415 HeapFree(GetProcessHeap(),0,ActionFormat);
417 ActionFormat = load_dynamic_stringW(row,3);
418 strcpyW(LastAction,action);
419 msiobj_release(&row->hdr);
420 MSI_ViewClose(view);
421 msiobj_release(&view->hdr);
424 message[0]=0;
425 ptr = ActionFormat;
426 while (*ptr)
428 LPWSTR ptr2;
429 LPWSTR data=NULL;
430 WCHAR tmp[1023];
431 INT field;
433 ptr2 = strchrW(ptr,'[');
434 if (ptr2)
436 strncpyW(tmp,ptr,ptr2-ptr);
437 tmp[ptr2-ptr]=0;
438 strcatW(message,tmp);
439 ptr2++;
440 field = atoiW(ptr2);
441 data = load_dynamic_stringW(record,field);
442 if (data)
444 strcatW(message,data);
445 HeapFree(GetProcessHeap(),0,data);
447 ptr=strchrW(ptr2,']');
448 ptr++;
450 else
452 strcatW(message,ptr);
453 break;
457 row = MSI_CreateRecord(1);
458 MSI_RecordSetStringW(row,1,message);
460 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
461 msiobj_release(&row->hdr);
465 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
467 static const WCHAR template_s[]=
468 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ','%','s','.',0};
469 static const WCHAR format[] =
470 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
471 static const WCHAR Query_t[] =
472 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
473 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
474 ' ','\'','%','s','\'',0};
475 WCHAR message[1024];
476 WCHAR timet[0x100];
477 UINT rc;
478 MSIQUERY * view;
479 MSIRECORD * row = 0;
480 WCHAR *ActionText=NULL;
481 WCHAR Query[1024];
483 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
485 sprintfW(Query,Query_t,action);
486 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
487 if (rc != ERROR_SUCCESS)
488 return;
489 rc = MSI_ViewExecute(view, 0);
490 if (rc != ERROR_SUCCESS)
492 MSI_ViewClose(view);
493 msiobj_release(&view->hdr);
494 return;
496 rc = MSI_ViewFetch(view,&row);
497 if (rc != ERROR_SUCCESS)
499 MSI_ViewClose(view);
500 msiobj_release(&view->hdr);
501 return;
504 ActionText = load_dynamic_stringW(row,2);
505 msiobj_release(&row->hdr);
506 MSI_ViewClose(view);
507 msiobj_release(&view->hdr);
509 sprintfW(message,template_s,timet,action,ActionText);
511 row = MSI_CreateRecord(1);
512 MSI_RecordSetStringW(row,1,message);
514 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
515 msiobj_release(&row->hdr);
516 HeapFree(GetProcessHeap(),0,ActionText);
519 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
520 UINT rc)
522 MSIRECORD * row;
523 static const WCHAR template_s[]=
524 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ','%','s',
525 '.',0};
526 static const WCHAR template_e[]=
527 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ','%','s',
528 '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ','%','i','.',0};
529 static const WCHAR format[] =
530 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
531 WCHAR message[1024];
532 WCHAR timet[0x100];
534 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
535 if (start)
536 sprintfW(message,template_s,timet,action);
537 else
538 sprintfW(message,template_e,timet,action,rc);
540 row = MSI_CreateRecord(1);
541 MSI_RecordSetStringW(row,1,message);
543 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
544 msiobj_release(&row->hdr);
547 /****************************************************
548 * TOP level entry points
549 *****************************************************/
551 UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
552 LPCWSTR szCommandLine)
554 DWORD sz;
555 WCHAR buffer[10];
556 UINT rc;
557 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
559 if (szPackagePath)
561 LPWSTR p;
562 WCHAR check[MAX_PATH];
563 WCHAR pth[MAX_PATH];
564 DWORD size;
566 strcpyW(pth,szPackagePath);
567 p = strrchrW(pth,'\\');
568 if (p)
570 p++;
571 *p=0;
574 size = MAX_PATH;
575 if (MSI_GetPropertyW(package,cszSourceDir,check,&size)
576 != ERROR_SUCCESS )
577 MSI_SetPropertyW(package, cszSourceDir, pth);
580 if (szCommandLine)
582 LPWSTR ptr,ptr2;
583 ptr = (LPWSTR)szCommandLine;
585 while (*ptr)
587 WCHAR prop[0x100];
588 WCHAR val[0x100];
590 TRACE("Looking at %s\n",debugstr_w(ptr));
592 ptr2 = strchrW(ptr,'=');
593 if (ptr2)
595 BOOL quote=FALSE;
596 DWORD len = 0;
597 strncpyW(prop,ptr,ptr2-ptr);
598 prop[ptr2-ptr]=0;
599 ptr2++;
601 ptr = ptr2;
602 while (*ptr && (quote || (!quote && *ptr!=' ')))
604 if (*ptr == '"')
605 quote = !quote;
606 ptr++;
607 len++;
610 if (*ptr2=='"')
612 ptr2++;
613 len -= 2;
615 strncpyW(val,ptr2,len);
616 val[len]=0;
618 if (*ptr)
619 ptr++;
621 TRACE("Found commandline property (%s) = (%s)\n", debugstr_w(prop),
622 debugstr_w(val));
623 MSI_SetPropertyW(package,prop,val);
627 sz = 10;
628 if (MSI_GetPropertyW(package,szUILevel,buffer,&sz) == ERROR_SUCCESS)
630 if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED)
632 rc = ACTION_ProcessUISequence(package);
633 if (rc == ERROR_SUCCESS)
634 rc = ACTION_ProcessExecSequence(package,TRUE);
636 else
637 rc = ACTION_ProcessExecSequence(package,FALSE);
639 else
640 rc = ACTION_ProcessExecSequence(package,FALSE);
642 return rc;
646 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
648 MSIQUERY * view;
649 UINT rc;
650 static const WCHAR ExecSeqQuery[] = {
651 's','e','l','e','c','t',' ','*',' ',
652 'f','r','o','m',' ',
653 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
654 'S','e','q','u','e','n','c','e',' ',
655 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
656 '>',' ','%','i',' ','o','r','d','e','r',' ',
657 'b','y',' ','S','e','q','u','e','n','c','e',0 };
658 WCHAR Query[1024];
659 MSIRECORD * row = 0;
660 static const WCHAR IVQuery[] = {
661 's','e','l','e','c','t',' ','S','e','q','u','e','n','c','e',' ',
662 'f','r','o','m',' ','I','n','s','t','a','l','l',
663 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e',' ',
664 'w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',' ',
665 '`','I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`',
668 if (UIran)
670 INT seq = 0;
672 rc = MSI_DatabaseOpenViewW(package->db, IVQuery, &view);
673 if (rc != ERROR_SUCCESS)
674 return rc;
675 rc = MSI_ViewExecute(view, 0);
676 if (rc != ERROR_SUCCESS)
678 MSI_ViewClose(view);
679 msiobj_release(&view->hdr);
680 return rc;
682 rc = MSI_ViewFetch(view,&row);
683 if (rc != ERROR_SUCCESS)
685 MSI_ViewClose(view);
686 msiobj_release(&view->hdr);
687 return rc;
689 seq = MSI_RecordGetInteger(row,1);
690 msiobj_release(&row->hdr);
691 MSI_ViewClose(view);
692 msiobj_release(&view->hdr);
693 sprintfW(Query,ExecSeqQuery,seq);
695 else
696 sprintfW(Query,ExecSeqQuery,0);
698 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
699 if (rc == ERROR_SUCCESS)
701 rc = MSI_ViewExecute(view, 0);
703 if (rc != ERROR_SUCCESS)
705 MSI_ViewClose(view);
706 msiobj_release(&view->hdr);
707 goto end;
710 TRACE("Running the actions \n");
712 while (1)
714 WCHAR buffer[0x100];
715 DWORD sz = 0x100;
717 rc = MSI_ViewFetch(view,&row);
718 if (rc != ERROR_SUCCESS)
720 rc = ERROR_SUCCESS;
721 break;
724 /* check conditions */
725 if (!MSI_RecordIsNull(row,2))
727 LPWSTR cond = NULL;
728 cond = load_dynamic_stringW(row,2);
730 if (cond)
732 /* this is a hack to skip errors in the condition code */
733 if (MSI_EvaluateConditionW(package, cond) ==
734 MSICONDITION_FALSE)
736 HeapFree(GetProcessHeap(),0,cond);
737 msiobj_release(&row->hdr);
738 continue;
740 else
741 HeapFree(GetProcessHeap(),0,cond);
745 sz=0x100;
746 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
747 if (rc != ERROR_SUCCESS)
749 ERR("Error is %x\n",rc);
750 msiobj_release(&row->hdr);
751 break;
754 rc = ACTION_PerformAction(package,buffer);
756 if (rc != ERROR_SUCCESS)
758 ERR("Execution halted due to error (%i)\n",rc);
759 msiobj_release(&row->hdr);
760 break;
763 msiobj_release(&row->hdr);
766 MSI_ViewClose(view);
767 msiobj_release(&view->hdr);
770 end:
771 return rc;
775 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
777 MSIQUERY * view;
778 UINT rc;
779 static const WCHAR ExecSeqQuery [] = {
780 's','e','l','e','c','t',' ','*',' ',
781 'f','r','o','m',' ','I','n','s','t','a','l','l',
782 'U','I','S','e','q','u','e','n','c','e',' ',
783 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', '>',' ','0',' ',
784 'o','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e',0};
786 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
788 if (rc == ERROR_SUCCESS)
790 rc = MSI_ViewExecute(view, 0);
792 if (rc != ERROR_SUCCESS)
794 MSI_ViewClose(view);
795 msiobj_release(&view->hdr);
796 goto end;
799 TRACE("Running the actions \n");
801 while (1)
803 WCHAR buffer[0x100];
804 DWORD sz = 0x100;
805 MSIRECORD * row = 0;
807 rc = MSI_ViewFetch(view,&row);
808 if (rc != ERROR_SUCCESS)
810 rc = ERROR_SUCCESS;
811 break;
814 /* check conditions */
815 if (!MSI_RecordIsNull(row,2))
817 LPWSTR cond = NULL;
818 cond = load_dynamic_stringW(row,2);
820 if (cond)
822 /* this is a hack to skip errors in the condition code */
823 if (MSI_EvaluateConditionW(package, cond) ==
824 MSICONDITION_FALSE)
826 HeapFree(GetProcessHeap(),0,cond);
827 msiobj_release(&row->hdr);
828 continue;
830 else
831 HeapFree(GetProcessHeap(),0,cond);
835 sz=0x100;
836 rc = MSI_RecordGetStringW(row,1,buffer,&sz);
837 if (rc != ERROR_SUCCESS)
839 ERR("Error is %x\n",rc);
840 msiobj_release(&row->hdr);
841 break;
844 rc = ACTION_PerformAction(package,buffer);
846 if (rc != ERROR_SUCCESS)
848 ERR("Execution halted due to error (%i)\n",rc);
849 msiobj_release(&row->hdr);
850 break;
853 msiobj_release(&row->hdr);
856 MSI_ViewClose(view);
857 msiobj_release(&view->hdr);
860 end:
861 return rc;
864 /********************************************************
865 * ACTION helper functions and functions that perform the actions
866 *******************************************************/
869 * Alot of actions are really important even if they don't do anything
870 * explicit.. Lots of properties are set at the beginning of the installation
871 * CostFinalize does a bunch of work to translated the directories and such
873 * But until I get write access to the database that is hard, so I am going to
874 * hack it to see if I can get something to run.
876 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action)
878 UINT rc = ERROR_SUCCESS;
880 TRACE("Performing action (%s)\n",debugstr_w(action));
881 ui_actioninfo(package, action, TRUE, 0);
882 ui_actionstart(package, action);
883 ui_progress(package,2,1,0,0);
885 /* pre install, setup and configuration block */
886 if (strcmpW(action,szLaunchConditions)==0)
887 rc = ACTION_LaunchConditions(package);
888 else if (strcmpW(action,szCostInitialize)==0)
889 rc = ACTION_CostInitialize(package);
890 else if (strcmpW(action,szFileCost)==0)
891 rc = ACTION_FileCost(package);
892 else if (strcmpW(action,szCostFinalize)==0)
893 rc = ACTION_CostFinalize(package);
894 else if (strcmpW(action,szInstallValidate)==0)
895 rc = ACTION_InstallValidate(package);
897 /* install block */
898 else if (strcmpW(action,szProcessComponents)==0)
899 rc = ACTION_ProcessComponents(package);
900 else if (strcmpW(action,szInstallInitialize)==0)
901 rc = ACTION_InstallInitialize(package);
902 else if (strcmpW(action,szCreateFolders)==0)
903 rc = ACTION_CreateFolders(package);
904 else if (strcmpW(action,szInstallFiles)==0)
905 rc = ACTION_InstallFiles(package);
906 else if (strcmpW(action,szDuplicateFiles)==0)
907 rc = ACTION_DuplicateFiles(package);
908 else if (strcmpW(action,szWriteRegistryValues)==0)
909 rc = ACTION_WriteRegistryValues(package);
910 else if (strcmpW(action,szRegisterTypeLibraries)==0)
911 rc = ACTION_RegisterTypeLibraries(package);
912 else if (strcmpW(action,szRegisterClassInfo)==0)
913 rc = ACTION_RegisterClassInfo(package);
914 else if (strcmpW(action,szRegisterProgIdInfo)==0)
915 rc = ACTION_RegisterProgIdInfo(package);
916 else if (strcmpW(action,szCreateShortcuts)==0)
917 rc = ACTION_CreateShortcuts(package);
918 else if (strcmpW(action,szPublishProduct)==0)
919 rc = ACTION_PublishProduct(package);
922 Called during iTunes but unimplemented and seem important
924 ResolveSource (sets SourceDir)
925 RegisterProduct
926 InstallFinalize
928 else if ((rc = ACTION_CustomAction(package,action)) != ERROR_SUCCESS)
930 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
931 rc = ERROR_SUCCESS;
934 ui_actioninfo(package, action, FALSE, rc);
935 return rc;
939 static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action)
941 UINT rc = ERROR_SUCCESS;
942 MSIQUERY * view;
943 MSIRECORD * row = 0;
944 WCHAR ExecSeqQuery[1024] =
945 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','C','u','s','t','o'
946 ,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i'
947 ,'o','n','`',' ','=',' ','`',0};
948 static const WCHAR end[]={'`',0};
949 UINT type;
950 LPWSTR source;
951 LPWSTR target;
952 WCHAR *deformated=NULL;
954 strcatW(ExecSeqQuery,action);
955 strcatW(ExecSeqQuery,end);
957 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
959 if (rc != ERROR_SUCCESS)
960 return rc;
962 rc = MSI_ViewExecute(view, 0);
963 if (rc != ERROR_SUCCESS)
965 MSI_ViewClose(view);
966 msiobj_release(&view->hdr);
967 return rc;
970 rc = MSI_ViewFetch(view,&row);
971 if (rc != ERROR_SUCCESS)
973 MSI_ViewClose(view);
974 msiobj_release(&view->hdr);
975 return rc;
978 type = MSI_RecordGetInteger(row,2);
980 source = load_dynamic_stringW(row,3);
981 target = load_dynamic_stringW(row,4);
983 TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type,
984 debugstr_w(source), debugstr_w(target));
986 /* we are ignoring ALOT of flags and important synchronization stuff */
987 switch (type & CUSTOM_ACTION_TYPE_MASK)
989 case 1: /* DLL file stored in a Binary table stream */
990 rc = HANDLE_CustomType1(package,source,target,type);
991 break;
992 case 2: /* EXE file stored in a Binary table strem */
993 rc = HANDLE_CustomType2(package,source,target,type);
994 break;
995 case 35: /* Directory set with formatted text. */
996 case 51: /* Property set with formatted text. */
997 deformat_string(package,target,&deformated);
998 rc = MSI_SetPropertyW(package,source,deformated);
999 HeapFree(GetProcessHeap(),0,deformated);
1000 break;
1001 default:
1002 FIXME("UNHANDLED ACTION TYPE %i (%s %s)\n",
1003 type & CUSTOM_ACTION_TYPE_MASK, debugstr_w(source),
1004 debugstr_w(target));
1007 HeapFree(GetProcessHeap(),0,source);
1008 HeapFree(GetProcessHeap(),0,target);
1009 msiobj_release(&row->hdr);
1010 MSI_ViewClose(view);
1011 msiobj_release(&view->hdr);
1012 return rc;
1015 static UINT store_binary_to_temp(MSIPACKAGE *package, const LPWSTR source,
1016 LPWSTR tmp_file)
1018 DWORD sz=MAX_PATH;
1020 if (MSI_GetPropertyW(package, cszTempFolder, tmp_file, &sz)
1021 != ERROR_SUCCESS)
1022 GetTempPathW(MAX_PATH,tmp_file);
1024 strcatW(tmp_file,source);
1026 if (GetFileAttributesW(tmp_file) != INVALID_FILE_ATTRIBUTES)
1028 TRACE("File already exists\n");
1029 return ERROR_SUCCESS;
1031 else
1033 /* write out the file */
1034 UINT rc;
1035 MSIQUERY * view;
1036 MSIRECORD * row = 0;
1037 WCHAR Query[1024] =
1038 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','B','i'
1039 ,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`',0};
1040 static const WCHAR end[]={'`',0};
1041 HANDLE the_file;
1042 CHAR buffer[1024];
1044 if (track_tempfile(package, source, tmp_file)!=0)
1045 FIXME("File Name in temp tracking collision\n");
1047 the_file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
1048 FILE_ATTRIBUTE_NORMAL, NULL);
1050 if (the_file == INVALID_HANDLE_VALUE)
1051 return ERROR_FUNCTION_FAILED;
1053 strcatW(Query,source);
1054 strcatW(Query,end);
1056 rc = MSI_DatabaseOpenViewW( package->db, Query, &view);
1057 if (rc != ERROR_SUCCESS)
1058 return rc;
1060 rc = MSI_ViewExecute(view, 0);
1061 if (rc != ERROR_SUCCESS)
1063 MSI_ViewClose(view);
1064 msiobj_release(&view->hdr);
1065 return rc;
1068 rc = MSI_ViewFetch(view,&row);
1069 if (rc != ERROR_SUCCESS)
1071 MSI_ViewClose(view);
1072 msiobj_release(&view->hdr);
1073 return rc;
1078 DWORD write;
1079 sz = 1024;
1080 rc = MSI_RecordReadStream(row,2,buffer,&sz);
1081 if (rc != ERROR_SUCCESS)
1083 ERR("Failed to get stream\n");
1084 CloseHandle(the_file);
1085 DeleteFileW(tmp_file);
1086 break;
1088 WriteFile(the_file,buffer,sz,&write,NULL);
1089 } while (sz == 1024);
1091 CloseHandle(the_file);
1093 msiobj_release(&row->hdr);
1094 MSI_ViewClose(view);
1095 msiobj_release(&view->hdr);
1098 return ERROR_SUCCESS;
1102 typedef UINT CustomEntry(MSIHANDLE);
1103 typedef struct
1105 MSIPACKAGE *package;
1106 WCHAR target[MAX_PATH];
1107 WCHAR source[MAX_PATH];
1108 } thread_struct;
1110 #if 0
1111 static DWORD WINAPI DllThread(LPVOID info)
1113 HANDLE DLL;
1114 LPSTR proc;
1115 thread_struct *stuff;
1116 CustomEntry *fn;
1118 stuff = (thread_struct*)info;
1120 TRACE("Asyncronous start (%s, %s) \n", debugstr_w(stuff->source),
1121 debugstr_w(stuff->target));
1123 DLL = LoadLibraryW(stuff->source);
1124 if (DLL)
1126 proc = strdupWtoA( stuff->target );
1127 fn = (CustomEntry*)GetProcAddress(DLL,proc);
1128 if (fn)
1130 MSIHANDLE hPackage;
1131 MSIPACKAGE *package = stuff->package;
1133 TRACE("Calling function\n");
1134 hPackage = msiobj_findhandle( &package->hdr );
1135 if( !hPackage )
1136 ERR("Handle for object %p not found\n", package );
1137 fn(hPackage);
1138 msiobj_release( &package->hdr );
1140 else
1141 ERR("Cannot load functon\n");
1143 HeapFree(GetProcessHeap(),0,proc);
1144 FreeLibrary(DLL);
1146 else
1147 ERR("Unable to load library\n");
1148 msiobj_release( &stuff->package->hdr );
1149 HeapFree( GetProcessHeap(), 0, info );
1150 return 0;
1152 #endif
1154 static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source,
1155 const LPWSTR target, const INT type)
1157 WCHAR tmp_file[MAX_PATH];
1158 CustomEntry *fn;
1159 HANDLE DLL;
1160 LPSTR proc;
1162 store_binary_to_temp(package, source, tmp_file);
1164 TRACE("Calling function %s from %s\n",debugstr_w(target),
1165 debugstr_w(tmp_file));
1167 if (!strchrW(tmp_file,'.'))
1169 static const WCHAR dot[]={'.',0};
1170 strcatW(tmp_file,dot);
1173 if (type & 0xc0)
1175 /* DWORD ThreadId; */
1176 thread_struct *info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) );
1178 /* msiobj_addref( &package->hdr ); */
1179 info->package = package;
1180 strcpyW(info->target,target);
1181 strcpyW(info->source,tmp_file);
1182 TRACE("Start Asyncronous execution\n");
1183 FIXME("DATABASE NOT THREADSAFE... not starting\n");
1184 /* CreateThread(NULL,0,DllThread,(LPVOID)&info,0,&ThreadId); */
1185 /* FIXME: release the package if the CreateThread fails */
1186 HeapFree( GetProcessHeap(), 0, info );
1187 return ERROR_SUCCESS;
1190 DLL = LoadLibraryW(tmp_file);
1191 if (DLL)
1193 proc = strdupWtoA( target );
1194 fn = (CustomEntry*)GetProcAddress(DLL,proc);
1195 if (fn)
1197 MSIHANDLE hPackage;
1199 TRACE("Calling function\n");
1200 hPackage = msiobj_findhandle( &package->hdr );
1201 if( !hPackage )
1202 ERR("Handle for object %p not found\n", package );
1203 fn(hPackage);
1204 msiobj_release( &package->hdr );
1206 else
1207 ERR("Cannot load functon\n");
1209 HeapFree(GetProcessHeap(),0,proc);
1210 FreeLibrary(DLL);
1212 else
1213 ERR("Unable to load library\n");
1215 return ERROR_SUCCESS;
1218 static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source,
1219 const LPWSTR target, const INT type)
1221 WCHAR tmp_file[MAX_PATH*2];
1222 STARTUPINFOW si;
1223 PROCESS_INFORMATION info;
1224 BOOL rc;
1225 WCHAR *deformated;
1226 static const WCHAR spc[] = {' ',0};
1228 memset(&si,0,sizeof(STARTUPINFOW));
1229 memset(&info,0,sizeof(PROCESS_INFORMATION));
1231 store_binary_to_temp(package, source, tmp_file);
1233 strcatW(tmp_file,spc);
1234 deformat_string(package,target,&deformated);
1235 strcatW(tmp_file,deformated);
1237 HeapFree(GetProcessHeap(),0,deformated);
1239 TRACE("executing exe %s \n",debugstr_w(tmp_file));
1241 rc = CreateProcessW(NULL, tmp_file, NULL, NULL, FALSE, 0, NULL,
1242 c_collen, &si, &info);
1244 if ( !rc )
1246 ERR("Unable to execute command\n");
1247 return ERROR_SUCCESS;
1250 if (!(type & 0xc0))
1251 WaitForSingleObject(info.hProcess,INFINITE);
1253 return ERROR_SUCCESS;
1256 /***********************************************************************
1257 * create_full_pathW
1259 * Recursively create all directories in the path.
1261 * shamelessly stolen from setupapi/queue.c
1263 static BOOL create_full_pathW(const WCHAR *path)
1265 BOOL ret = TRUE;
1266 int len;
1267 WCHAR *new_path;
1269 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *
1270 sizeof(WCHAR));
1271 strcpyW(new_path, path);
1273 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
1274 new_path[len - 1] = 0;
1276 while(!CreateDirectoryW(new_path, NULL))
1278 WCHAR *slash;
1279 DWORD last_error = GetLastError();
1280 if(last_error == ERROR_ALREADY_EXISTS)
1281 break;
1283 if(last_error != ERROR_PATH_NOT_FOUND)
1285 ret = FALSE;
1286 break;
1289 if(!(slash = strrchrW(new_path, '\\')))
1291 ret = FALSE;
1292 break;
1295 len = slash - new_path;
1296 new_path[len] = 0;
1297 if(!create_full_pathW(new_path))
1299 ret = FALSE;
1300 break;
1302 new_path[len] = '\\';
1305 HeapFree(GetProcessHeap(), 0, new_path);
1306 return ret;
1310 * Also we cannot enable/disable components either, so for now I am just going
1311 * to do all the directories for all the components.
1313 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1315 static const WCHAR ExecSeqQuery[] = {
1316 's','e','l','e','c','t',' ','D','i','r','e','c','t','o','r','y','_',' ',
1317 'f','r','o','m',' ','C','r','e','a','t','e','F','o','l','d','e','r',0 };
1318 UINT rc;
1319 MSIQUERY *view;
1320 MSIFOLDER *folder;
1322 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1323 if (rc != ERROR_SUCCESS)
1324 return rc;
1326 rc = MSI_ViewExecute(view, 0);
1327 if (rc != ERROR_SUCCESS)
1329 MSI_ViewClose(view);
1330 msiobj_release(&view->hdr);
1331 return rc;
1334 while (1)
1336 WCHAR dir[0x100];
1337 WCHAR full_path[MAX_PATH];
1338 DWORD sz;
1339 MSIRECORD *row = NULL, *uirow;
1341 rc = MSI_ViewFetch(view,&row);
1342 if (rc != ERROR_SUCCESS)
1344 rc = ERROR_SUCCESS;
1345 break;
1348 sz=0x100;
1349 rc = MSI_RecordGetStringW(row,1,dir,&sz);
1351 if (rc!= ERROR_SUCCESS)
1353 ERR("Unable to get folder id \n");
1354 msiobj_release(&row->hdr);
1355 continue;
1358 sz = MAX_PATH;
1359 rc = resolve_folder(package,dir,full_path,FALSE,FALSE,&folder);
1361 if (rc != ERROR_SUCCESS)
1363 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1364 msiobj_release(&row->hdr);
1365 continue;
1368 TRACE("Folder is %s\n",debugstr_w(full_path));
1370 /* UI stuff */
1371 uirow = MSI_CreateRecord(1);
1372 MSI_RecordSetStringW(uirow,1,full_path);
1373 ui_actiondata(package,szCreateFolders,uirow);
1374 msiobj_release( &uirow->hdr );
1376 if (folder->State == 0)
1377 create_full_pathW(full_path);
1379 folder->State = 3;
1381 msiobj_release(&row->hdr);
1383 MSI_ViewClose(view);
1384 msiobj_release(&view->hdr);
1386 return rc;
1389 static int load_component(MSIPACKAGE* package, MSIRECORD * row)
1391 int index = package->loaded_components;
1392 DWORD sz;
1394 /* fill in the data */
1396 package->loaded_components++;
1397 if (package->loaded_components == 1)
1398 package->components = HeapAlloc(GetProcessHeap(),0,
1399 sizeof(MSICOMPONENT));
1400 else
1401 package->components = HeapReAlloc(GetProcessHeap(),0,
1402 package->components, package->loaded_components *
1403 sizeof(MSICOMPONENT));
1405 memset(&package->components[index],0,sizeof(MSICOMPONENT));
1407 sz = 96;
1408 MSI_RecordGetStringW(row,1,package->components[index].Component,&sz);
1410 TRACE("Loading Component %s\n",
1411 debugstr_w(package->components[index].Component));
1413 sz = 0x100;
1414 if (!MSI_RecordIsNull(row,2))
1415 MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz);
1417 sz = 96;
1418 MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz);
1420 package->components[index].Attributes = MSI_RecordGetInteger(row,4);
1422 sz = 0x100;
1423 MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz);
1425 sz = 96;
1426 MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);
1428 package->components[index].State = INSTALLSTATE_UNKNOWN;
1429 package->components[index].Enabled = TRUE;
1430 package->components[index].FeatureState= FALSE;
1432 return index;
1435 static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
1437 int index = package->loaded_features;
1438 DWORD sz;
1439 static const WCHAR Query1[] = {'S','E','L','E','C','T',' ','C','o','m','p',
1440 'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',
1441 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',
1442 'a','t','u','r','e','_','=','\'','%','s','\'',0};
1443 static const WCHAR Query2[] = {'S','E','L','E','C','T',' ','*',' ','F','R',
1444 'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',
1445 'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};
1446 WCHAR Query[1024];
1447 MSIQUERY * view;
1448 MSIQUERY * view2;
1449 MSIRECORD * row2;
1450 MSIRECORD * row3;
1451 UINT rc;
1453 /* fill in the data */
1455 package->loaded_features ++;
1456 if (package->loaded_features == 1)
1457 package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE));
1458 else
1459 package->features = HeapReAlloc(GetProcessHeap(),0,package->features,
1460 package->loaded_features * sizeof(MSIFEATURE));
1462 memset(&package->features[index],0,sizeof(MSIFEATURE));
1464 sz = 96;
1465 MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz);
1467 TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature));
1469 sz = 96;
1470 if (!MSI_RecordIsNull(row,2))
1471 MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz);
1473 sz = 0x100;
1474 if (!MSI_RecordIsNull(row,3))
1475 MSI_RecordGetStringW(row,3,package->features[index].Title,&sz);
1477 sz = 0x100;
1478 if (!MSI_RecordIsNull(row,4))
1479 MSI_RecordGetStringW(row,4,package->features[index].Description,&sz);
1481 if (!MSI_RecordIsNull(row,5))
1482 package->features[index].Display = MSI_RecordGetInteger(row,5);
1484 package->features[index].Level= MSI_RecordGetInteger(row,6);
1486 sz = 96;
1487 if (!MSI_RecordIsNull(row,7))
1488 MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);
1490 package->features[index].Attributes= MSI_RecordGetInteger(row,8);
1491 package->features[index].State = INSTALLSTATE_UNKNOWN;
1493 /* load feature components */
1495 sprintfW(Query,Query1,package->features[index].Feature);
1496 rc = MSI_DatabaseOpenViewW(package->db,Query,&view);
1497 if (rc != ERROR_SUCCESS)
1498 return;
1499 rc = MSI_ViewExecute(view,0);
1500 if (rc != ERROR_SUCCESS)
1502 MSI_ViewClose(view);
1503 msiobj_release(&view->hdr);
1504 return;
1506 while (1)
1508 DWORD sz = 0x100;
1509 WCHAR buffer[0x100];
1510 DWORD rc;
1511 INT c_indx;
1512 INT cnt = package->features[index].ComponentCount;
1514 rc = MSI_ViewFetch(view,&row2);
1515 if (rc != ERROR_SUCCESS)
1516 break;
1518 sz = 0x100;
1519 MSI_RecordGetStringW(row2,1,buffer,&sz);
1521 /* check to see if the component is already loaded */
1522 c_indx = get_loaded_component(package,buffer);
1523 if (c_indx != -1)
1525 TRACE("Component %s already loaded at %i\n", debugstr_w(buffer),
1526 c_indx);
1527 package->features[index].Components[cnt] = c_indx;
1528 package->features[index].ComponentCount ++;
1531 sprintfW(Query,Query2,buffer);
1533 rc = MSI_DatabaseOpenViewW(package->db,Query,&view2);
1534 if (rc != ERROR_SUCCESS)
1536 msiobj_release( &row2->hdr );
1537 continue;
1539 rc = MSI_ViewExecute(view2,0);
1540 if (rc != ERROR_SUCCESS)
1542 msiobj_release( &row2->hdr );
1543 MSI_ViewClose(view2);
1544 msiobj_release( &view2->hdr );
1545 continue;
1547 while (1)
1549 DWORD rc;
1551 rc = MSI_ViewFetch(view2,&row3);
1552 if (rc != ERROR_SUCCESS)
1553 break;
1554 c_indx = load_component(package,row3);
1555 msiobj_release( &row3->hdr );
1557 package->features[index].Components[cnt] = c_indx;
1558 package->features[index].ComponentCount ++;
1560 MSI_ViewClose(view2);
1561 msiobj_release( &view2->hdr );
1562 msiobj_release( &row2->hdr );
1564 MSI_ViewClose(view);
1565 msiobj_release(&view->hdr);
1569 * I am not doing any of the costing functionality yet.
1570 * Mostly looking at doing the Component and Feature loading
1572 * The native MSI does ALOT of modification to tables here. Mostly adding alot
1573 * of temporary columns to the Feature and Component tables.
1575 * note: native msi also tracks the short filename. but I am only going to
1576 * track the long ones. Also looking at this directory table
1577 * it appears that the directory table does not get the parents
1578 * resolved base on property only based on their entrys in the
1579 * directory table.
1581 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1583 MSIQUERY * view;
1584 MSIRECORD * row;
1585 DWORD sz;
1586 UINT rc;
1587 static const WCHAR Query_all[] = {
1588 'S','E','L','E','C','T',' ','*',' ',
1589 'F','R','O','M',' ','F','e','a','t','u','r','e',0};
1590 static const WCHAR szCosting[] = {
1591 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1592 static const WCHAR szZero[] = { '0', 0 };
1594 MSI_SetPropertyW(package, szCosting, szZero);
1595 MSI_SetPropertyW(package, cszRootDrive , c_collen);
1597 sz = 0x100;
1598 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1599 if (rc != ERROR_SUCCESS)
1600 return rc;
1601 rc = MSI_ViewExecute(view,0);
1602 if (rc != ERROR_SUCCESS)
1604 MSI_ViewClose(view);
1605 msiobj_release(&view->hdr);
1606 return rc;
1608 while (1)
1610 DWORD rc;
1612 rc = MSI_ViewFetch(view,&row);
1613 if (rc != ERROR_SUCCESS)
1614 break;
1616 load_feature(package,row);
1617 msiobj_release(&row->hdr);
1619 MSI_ViewClose(view);
1620 msiobj_release(&view->hdr);
1622 return ERROR_SUCCESS;
1625 static int load_file(MSIPACKAGE* package, MSIRECORD * row)
1627 int index = package->loaded_files;
1628 int i;
1629 WCHAR buffer[0x100];
1630 DWORD sz;
1632 /* fill in the data */
1634 package->loaded_files++;
1635 if (package->loaded_files== 1)
1636 package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
1637 else
1638 package->files = HeapReAlloc(GetProcessHeap(),0,
1639 package->files , package->loaded_files * sizeof(MSIFILE));
1641 memset(&package->files[index],0,sizeof(MSIFILE));
1643 sz = 72;
1644 MSI_RecordGetStringW(row,1,package->files[index].File,&sz);
1646 sz = 0x100;
1647 MSI_RecordGetStringW(row,2,buffer,&sz);
1649 package->files[index].ComponentIndex = -1;
1650 for (i = 0; i < package->loaded_components; i++)
1651 if (strcmpW(package->components[i].Component,buffer)==0)
1653 package->files[index].ComponentIndex = i;
1654 break;
1656 if (package->files[index].ComponentIndex == -1)
1657 ERR("Unfound Component %s\n",debugstr_w(buffer));
1659 sz = MAX_PATH;
1660 MSI_RecordGetStringW(row,3,package->files[index].FileName,&sz);
1662 reduce_to_longfilename(package->files[index].FileName);
1664 package->files[index].FileSize = MSI_RecordGetInteger(row,4);
1666 sz = 72;
1667 if (!MSI_RecordIsNull(row,5))
1668 MSI_RecordGetStringW(row,5,package->files[index].Version,&sz);
1670 sz = 20;
1671 if (!MSI_RecordIsNull(row,6))
1672 MSI_RecordGetStringW(row,6,package->files[index].Language,&sz);
1674 if (!MSI_RecordIsNull(row,7))
1675 package->files[index].Attributes= MSI_RecordGetInteger(row,7);
1677 package->files[index].Sequence= MSI_RecordGetInteger(row,8);
1679 package->files[index].Temporary = FALSE;
1680 package->files[index].State = 0;
1682 TRACE("File Loaded (%s)\n",debugstr_w(package->files[index].File));
1684 return ERROR_SUCCESS;
1687 static UINT ACTION_FileCost(MSIPACKAGE *package)
1689 MSIQUERY * view;
1690 MSIRECORD * row;
1691 UINT rc;
1692 static const WCHAR Query[] = {
1693 'S','E','L','E','C','T',' ','*',' ',
1694 'F','R','O','M',' ','F','i','l','e',' ',
1695 'O','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e', 0};
1697 if (!package)
1698 return ERROR_INVALID_HANDLE;
1700 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1701 if (rc != ERROR_SUCCESS)
1702 return rc;
1704 rc = MSI_ViewExecute(view, 0);
1705 if (rc != ERROR_SUCCESS)
1707 MSI_ViewClose(view);
1708 msiobj_release(&view->hdr);
1709 return rc;
1712 while (1)
1714 rc = MSI_ViewFetch(view,&row);
1715 if (rc != ERROR_SUCCESS)
1717 rc = ERROR_SUCCESS;
1718 break;
1720 load_file(package,row);
1721 msiobj_release(&row->hdr);
1723 MSI_ViewClose(view);
1724 msiobj_release(&view->hdr);
1726 return ERROR_SUCCESS;
1729 static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)
1732 WCHAR Query[1024] =
1733 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',
1734 't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',
1735 'o','r','y','`',' ','=',' ','`',0};
1736 static const WCHAR end[]={'`',0};
1737 UINT rc;
1738 MSIQUERY * view;
1739 WCHAR targetbuffer[0x100];
1740 WCHAR *srcdir = NULL;
1741 WCHAR *targetdir = NULL;
1742 WCHAR parent[0x100];
1743 DWORD sz=0x100;
1744 MSIRECORD * row = 0;
1745 INT i,index = -1;
1747 TRACE("Looking for dir %s\n",debugstr_w(dir));
1749 for (i = 0; i < package->loaded_folders; i++)
1751 if (strcmpW(package->folders[i].Directory,dir)==0)
1753 TRACE(" %s retuning on index %i\n",debugstr_w(dir),i);
1754 return i;
1758 TRACE("Working to load %s\n",debugstr_w(dir));
1760 index = package->loaded_folders;
1762 package->loaded_folders++;
1763 if (package->loaded_folders== 1)
1764 package->folders = HeapAlloc(GetProcessHeap(),0,
1765 sizeof(MSIFOLDER));
1766 else
1767 package->folders= HeapReAlloc(GetProcessHeap(),0,
1768 package->folders, package->loaded_folders*
1769 sizeof(MSIFOLDER));
1771 memset(&package->folders[index],0,sizeof(MSIFOLDER));
1773 strcpyW(package->folders[index].Directory,dir);
1775 strcatW(Query,dir);
1776 strcatW(Query,end);
1778 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1780 if (rc != ERROR_SUCCESS)
1781 return -1;
1783 rc = MSI_ViewExecute(view, 0);
1784 if (rc != ERROR_SUCCESS)
1786 MSI_ViewClose(view);
1787 msiobj_release(&view->hdr);
1788 return -1;
1791 rc = MSI_ViewFetch(view,&row);
1792 if (rc != ERROR_SUCCESS)
1794 MSI_ViewClose(view);
1795 msiobj_release(&view->hdr);
1796 return -1;
1799 sz=0x100;
1800 MSI_RecordGetStringW(row,3,targetbuffer,&sz);
1801 targetdir=targetbuffer;
1803 /* split src and target dir */
1804 if (strchrW(targetdir,':'))
1806 srcdir=strchrW(targetdir,':');
1807 *srcdir=0;
1808 srcdir ++;
1810 else
1811 srcdir=NULL;
1813 /* for now only pick long filename versions */
1814 if (strchrW(targetdir,'|'))
1816 targetdir = strchrW(targetdir,'|');
1817 *targetdir = 0;
1818 targetdir ++;
1820 if (srcdir && strchrW(srcdir,'|'))
1822 srcdir= strchrW(srcdir,'|');
1823 *srcdir= 0;
1824 srcdir ++;
1827 /* now check for root dirs */
1828 if (targetdir[0] == '.' && targetdir[1] == 0)
1829 targetdir = NULL;
1831 if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
1832 srcdir = NULL;
1834 if (targetdir)
1835 strcpyW(package->folders[index].TargetDefault,targetdir);
1837 if (srcdir)
1838 strcpyW(package->folders[index].SourceDefault,srcdir);
1839 else if (targetdir)
1840 strcpyW(package->folders[index].SourceDefault,targetdir);
1842 if (MSI_RecordIsNull(row,2))
1843 parent[0]=0;
1844 else
1846 sz=0x100;
1847 MSI_RecordGetStringW(row,2,parent,&sz);
1850 if (parent[0])
1852 i = load_folder(package,parent);
1853 package->folders[index].ParentIndex = i;
1854 TRACE("Parent is index %i... %s %s\n",
1855 package->folders[index].ParentIndex,
1856 debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),
1857 debugstr_w(parent));
1859 else
1860 package->folders[index].ParentIndex = -2;
1862 sz = MAX_PATH;
1863 rc = MSI_GetPropertyW(package, dir, package->folders[index].Property, &sz);
1864 if (rc != ERROR_SUCCESS)
1865 package->folders[index].Property[0]=0;
1867 msiobj_release(&row->hdr);
1868 MSI_ViewClose(view);
1869 msiobj_release(&view->hdr);
1870 TRACE(" %s retuning on index %i\n",debugstr_w(dir),index);
1871 return index;
1874 static UINT resolve_folder(MSIPACKAGE *package, LPCWSTR name, LPWSTR path,
1875 BOOL source, BOOL set_prop, MSIFOLDER **folder)
1877 INT i;
1878 UINT rc = ERROR_SUCCESS;
1879 DWORD sz;
1881 TRACE("Working to resolve %s\n",debugstr_w(name));
1883 if (!path)
1884 return rc;
1886 /* special resolving for Target and Source root dir */
1887 if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
1889 if (!source)
1891 sz = MAX_PATH;
1892 rc = MSI_GetPropertyW(package,cszTargetDir,path,&sz);
1893 if (rc != ERROR_SUCCESS)
1895 sz = MAX_PATH;
1896 rc = MSI_GetPropertyW(package,cszRootDrive,path,&sz);
1897 if (set_prop)
1898 MSI_SetPropertyW(package,cszTargetDir,path);
1900 if (folder)
1901 *folder = &(package->folders[0]);
1902 return rc;
1904 else
1906 sz = MAX_PATH;
1907 rc = MSI_GetPropertyW(package,cszSourceDir,path,&sz);
1908 if (rc != ERROR_SUCCESS)
1910 sz = MAX_PATH;
1911 rc = MSI_GetPropertyW(package,cszDatabase,path,&sz);
1912 if (rc == ERROR_SUCCESS)
1914 LPWSTR ptr = strrchrW(path,'\\');
1915 if (ptr)
1917 ptr++;
1918 *ptr = 0;
1922 if (folder)
1923 *folder = &(package->folders[0]);
1924 return rc;
1928 for (i = 0; i < package->loaded_folders; i++)
1930 if (strcmpW(package->folders[i].Directory,name)==0)
1931 break;
1934 if (i >= package->loaded_folders)
1935 return ERROR_FUNCTION_FAILED;
1937 if (folder)
1938 *folder = &(package->folders[i]);
1940 if (!source && package->folders[i].ResolvedTarget[0])
1942 strcpyW(path,package->folders[i].ResolvedTarget);
1943 TRACE(" already resolved to %s\n",debugstr_w(path));
1944 return ERROR_SUCCESS;
1946 else if (source && package->folders[i].ResolvedSource[0])
1948 strcpyW(path,package->folders[i].ResolvedSource);
1949 return ERROR_SUCCESS;
1951 else if (!source && package->folders[i].Property[0])
1953 strcpyW(path,package->folders[i].Property);
1954 TRACE(" internally set to %s\n",debugstr_w(path));
1955 if (set_prop)
1956 MSI_SetPropertyW(package,name,path);
1957 return ERROR_SUCCESS;
1960 if (package->folders[i].ParentIndex >= 0)
1962 TRACE(" ! Parent is %s\n", debugstr_w(package->folders[
1963 package->folders[i].ParentIndex].Directory));
1964 resolve_folder(package, package->folders[
1965 package->folders[i].ParentIndex].Directory, path,source,
1966 set_prop, NULL);
1968 if (!source)
1970 if (package->folders[i].TargetDefault[0])
1972 strcatW(path,package->folders[i].TargetDefault);
1973 strcatW(path,cszbs);
1975 strcpyW(package->folders[i].ResolvedTarget,path);
1976 TRACE(" resolved into %s\n",debugstr_w(path));
1977 if (set_prop)
1978 MSI_SetPropertyW(package,name,path);
1980 else
1982 if (package->folders[i].SourceDefault[0])
1984 strcatW(path,package->folders[i].SourceDefault);
1985 strcatW(path,cszbs);
1987 strcpyW(package->folders[i].ResolvedSource,path);
1990 return rc;
1994 * Alot is done in this function aside from just the costing.
1995 * The costing needs to be implemented at some point but for now I am going
1996 * to focus on the directory building
1999 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2001 static const WCHAR ExecSeqQuery[] = {
2002 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2003 'D','i','r','e','c','t','o','r','y',0};
2004 static const WCHAR ConditionQuery[] = {
2005 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2006 'C','o','n','d','i','t','i','o','n',0};
2007 static const WCHAR szCosting[] = {
2008 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2009 static const WCHAR szOne[] = { '1', 0 };
2010 UINT rc;
2011 MSIQUERY * view;
2012 INT i;
2014 TRACE("Building Directory properties\n");
2016 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2017 if (rc != ERROR_SUCCESS)
2018 return rc;
2020 rc = MSI_ViewExecute(view, 0);
2021 if (rc != ERROR_SUCCESS)
2023 MSI_ViewClose(view);
2024 msiobj_release(&view->hdr);
2025 return rc;
2028 while (1)
2030 WCHAR name[0x100];
2031 WCHAR path[MAX_PATH];
2032 MSIRECORD * row = 0;
2033 DWORD sz;
2035 rc = MSI_ViewFetch(view,&row);
2036 if (rc != ERROR_SUCCESS)
2038 rc = ERROR_SUCCESS;
2039 break;
2042 sz=0x100;
2043 MSI_RecordGetStringW(row,1,name,&sz);
2045 /* This helper function now does ALL the work */
2046 TRACE("Dir %s ...\n",debugstr_w(name));
2047 load_folder(package,name);
2048 resolve_folder(package,name,path,FALSE,TRUE,NULL);
2049 TRACE("resolves to %s\n",debugstr_w(path));
2051 msiobj_release(&row->hdr);
2053 MSI_ViewClose(view);
2054 msiobj_release(&view->hdr);
2056 TRACE("File calculations %i files\n",package->loaded_files);
2058 for (i = 0; i < package->loaded_files; i++)
2060 MSICOMPONENT* comp = NULL;
2061 MSIFILE* file= NULL;
2063 file = &package->files[i];
2064 if (file->ComponentIndex >= 0)
2065 comp = &package->components[file->ComponentIndex];
2067 if (comp)
2069 /* calculate target */
2070 resolve_folder(package, comp->Directory, file->TargetPath, FALSE,
2071 FALSE, NULL);
2072 strcatW(file->TargetPath,file->FileName);
2074 TRACE("file %s resolves to %s\n",
2075 debugstr_w(file->File),debugstr_w(file->TargetPath));
2077 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2079 file->State = 1;
2080 comp->Cost += file->FileSize;
2082 else
2084 if (file->Version[0])
2086 DWORD handle;
2087 DWORD versize;
2088 UINT sz;
2089 LPVOID version;
2090 WCHAR filever[0x100];
2091 static const WCHAR name[] =
2092 {'\\','V','a','r','F','i','l','e','I','n','f','o',
2093 '\\','F','i','l','e','V','e','r','s','i','o','n',0};
2095 FIXME("Version comparison.. Untried Untested and most "
2096 "likely very very wrong\n");
2097 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
2098 version = HeapAlloc(GetProcessHeap(),0,versize);
2099 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
2100 sz = 0x100;
2101 VerQueryValueW(version,name,(LPVOID)filever,&sz);
2102 HeapFree(GetProcessHeap(),0,version);
2104 if (strcmpW(version,file->Version)<0)
2106 file->State = 2;
2107 FIXME("cost should be diff in size\n");
2108 comp->Cost += file->FileSize;
2110 else
2111 file->State = 3;
2113 else
2114 file->State = 3;
2119 TRACE("Evaluating Condition Table\n");
2121 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2122 if (rc != ERROR_SUCCESS)
2123 return rc;
2125 rc = MSI_ViewExecute(view, 0);
2126 if (rc != ERROR_SUCCESS)
2128 MSI_ViewClose(view);
2129 msiobj_release(&view->hdr);
2130 return rc;
2133 while (1)
2135 WCHAR Feature[0x100];
2136 MSIRECORD * row = 0;
2137 DWORD sz;
2138 int feature_index;
2140 rc = MSI_ViewFetch(view,&row);
2142 if (rc != ERROR_SUCCESS)
2144 rc = ERROR_SUCCESS;
2145 break;
2148 sz = 0x100;
2149 MSI_RecordGetStringW(row,1,Feature,&sz);
2151 feature_index = get_loaded_feature(package,Feature);
2152 if (feature_index < 0)
2153 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));
2154 else
2156 LPWSTR Condition;
2157 Condition = load_dynamic_stringW(row,3);
2159 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2161 int level = MSI_RecordGetInteger(row,2);
2162 TRACE("Reseting feature %s to level %i\n",debugstr_w(Feature),
2163 level);
2164 package->features[feature_index].Level = level;
2166 HeapFree(GetProcessHeap(),0,Condition);
2169 msiobj_release(&row->hdr);
2171 MSI_ViewClose(view);
2172 msiobj_release(&view->hdr);
2174 TRACE("Enabling or Disabling Components\n");
2175 for (i = 0; i < package->loaded_components; i++)
2177 if (package->components[i].Condition[0])
2179 if (MSI_EvaluateConditionW(package,
2180 package->components[i].Condition) == MSICONDITION_FALSE)
2182 TRACE("Disabling component %s\n",
2183 debugstr_w(package->components[i].Component));
2184 package->components[i].Enabled = FALSE;
2189 MSI_SetPropertyW(package,szCosting,szOne);
2190 return ERROR_SUCCESS;
2194 * This is a helper function for handling embedded cabinet media
2196 static UINT writeout_cabinet_stream(MSIPACKAGE *package, WCHAR* stream_name,
2197 WCHAR* source)
2199 UINT rc;
2200 USHORT* data;
2201 UINT size;
2202 DWORD write;
2203 HANDLE the_file;
2204 WCHAR tmp[MAX_PATH];
2206 rc = read_raw_stream_data(package->db,stream_name,&data,&size);
2207 if (rc != ERROR_SUCCESS)
2208 return rc;
2210 write = MAX_PATH;
2211 if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
2212 GetTempPathW(MAX_PATH,tmp);
2214 GetTempFileNameW(tmp,stream_name,0,source);
2216 track_tempfile(package,strrchrW(source,'\\'), source);
2217 the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2218 FILE_ATTRIBUTE_NORMAL, NULL);
2220 if (the_file == INVALID_HANDLE_VALUE)
2222 rc = ERROR_FUNCTION_FAILED;
2223 goto end;
2226 WriteFile(the_file,data,size,&write,NULL);
2227 CloseHandle(the_file);
2228 TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
2229 end:
2230 HeapFree(GetProcessHeap(),0,data);
2231 return rc;
2235 /***********************************************************************
2236 * extract_cabinet_file
2238 * Extract files from a cab file.
2240 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
2242 static BOOL extract_cabinet_file_advpack( const WCHAR *cabinet,
2243 const WCHAR *root)
2245 static HMODULE advpack;
2247 char *cab_path, *cab_file;
2249 if (!pExtractFiles)
2251 if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
2253 ERR( "could not load advpack.dll\n" );
2254 return FALSE;
2256 if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles"
2259 ERR( "could not find ExtractFiles in advpack.dll\n" );
2260 return FALSE;
2264 if (!(cab_file = strdupWtoA( cabinet ))) return FALSE;
2265 if (!(cab_path = strdupWtoA( root ))) return FALSE;
2267 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
2268 pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
2269 HeapFree( GetProcessHeap(), 0, cab_file );
2270 HeapFree( GetProcessHeap(), 0, cab_path );
2271 return TRUE;
2274 static BOOL extract_cabinet_file_cabinet( const WCHAR *cabinet,
2275 const WCHAR *root)
2278 /* from cabinet.h */
2280 struct ExtractFileList {
2281 LPSTR filename;
2282 struct ExtractFileList *next;
2283 BOOL unknown; /* always 1L */
2286 typedef struct {
2287 long result1; /* 0x000 */
2288 long unknown1[3]; /* 0x004 */
2289 struct ExtractFileList* filelist; /* 0x010 */
2290 long filecount; /* 0x014 */
2291 long unknown2; /* 0x018 */
2292 char directory[0x104]; /* 0x01c */
2293 char lastfile[0x20c]; /* 0x120 */
2294 } EXTRACTdest;
2296 HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR what);
2298 char *cab_path, *src_path;
2299 EXTRACTdest exd;
2300 struct ExtractFileList fl;
2302 if (!(cab_path = strdupWtoA( cabinet ))) return FALSE;
2303 if (!(src_path = strdupWtoA( root ))) return FALSE;
2305 memset(&exd,0,sizeof(exd));
2306 strcpy(exd.directory,src_path);
2307 exd.unknown2 = 0x1;
2308 fl.filename = cab_path;
2309 fl.next = NULL;
2310 fl.unknown = 1;
2311 exd.filelist = &fl;
2312 FIXME( "more aweful hack: extracting cabinet %s\n", debugstr_a(cab_path) );
2313 Extract(&exd,cab_path);
2315 HeapFree( GetProcessHeap(), 0, cab_path );
2316 HeapFree( GetProcessHeap(), 0, src_path );
2317 return TRUE;
2320 static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path)
2322 TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));
2323 if (!extract_cabinet_file_advpack(source,path))
2324 return extract_cabinet_file_cabinet(source,path);
2325 return TRUE;
2328 static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence,
2329 WCHAR* path)
2331 UINT rc;
2332 MSIQUERY * view;
2333 MSIRECORD * row = 0;
2334 WCHAR source[MAX_PATH];
2335 static const WCHAR ExecSeqQuery[] = {
2336 's','e','l','e','c','t',' ','*',' ',
2337 'f','r','o','m',' ','M','e','d','i','a',' ',
2338 'w','h','e','r','e',' ','L','a','s','t','S','e','q','u','e','n','c','e',' ','>','=',' ','%','i',' ',
2339 'o','r','d','e','r',' ','b','y',' ','L','a','s','t','S','e','q','u','e','n','c','e',0};
2340 WCHAR Query[1024];
2341 WCHAR cab[0x100];
2342 DWORD sz=0x100;
2343 INT seq;
2344 static INT last_sequence = 0;
2346 if (sequence <= last_sequence)
2348 TRACE("Media already ready (%i, %i)\n",sequence,last_sequence);
2349 return ERROR_SUCCESS;
2352 sprintfW(Query,ExecSeqQuery,sequence);
2354 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2355 if (rc != ERROR_SUCCESS)
2356 return rc;
2358 rc = MSI_ViewExecute(view, 0);
2359 if (rc != ERROR_SUCCESS)
2361 MSI_ViewClose(view);
2362 msiobj_release(&view->hdr);
2363 return rc;
2366 rc = MSI_ViewFetch(view,&row);
2367 if (rc != ERROR_SUCCESS)
2369 MSI_ViewClose(view);
2370 msiobj_release(&view->hdr);
2371 return rc;
2373 seq = MSI_RecordGetInteger(row,2);
2374 last_sequence = seq;
2376 if (!MSI_RecordIsNull(row,4))
2378 sz=0x100;
2379 MSI_RecordGetStringW(row,4,cab,&sz);
2380 TRACE("Source is CAB %s\n",debugstr_w(cab));
2381 /* the stream does not contain the # character */
2382 if (cab[0]=='#')
2384 writeout_cabinet_stream(package,&cab[1],source);
2385 strcpyW(path,source);
2386 *(strrchrW(path,'\\')+1)=0;
2388 else
2390 sz = MAX_PATH;
2391 if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
2393 ERR("No Source dir defined \n");
2394 rc = ERROR_FUNCTION_FAILED;
2396 else
2398 strcpyW(path,source);
2399 strcatW(source,cab);
2400 /* extract the cab file into a folder in the temp folder */
2401 sz = MAX_PATH;
2402 if (MSI_GetPropertyW(package, cszTempFolder,path, &sz)
2403 != ERROR_SUCCESS)
2404 GetTempPathW(MAX_PATH,path);
2407 rc = !extract_cabinet_file(source,path);
2409 msiobj_release(&row->hdr);
2410 MSI_ViewClose(view);
2411 msiobj_release(&view->hdr);
2412 return rc;
2415 inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
2417 UINT rc;
2418 MSIFOLDER *folder;
2419 WCHAR install_path[MAX_PATH];
2421 rc = resolve_folder(package, package->components[component].Directory,
2422 install_path, FALSE, FALSE, &folder);
2424 if (rc != ERROR_SUCCESS)
2425 return rc;
2427 /* create the path */
2428 if (folder->State == 0)
2430 create_full_pathW(install_path);
2431 folder->State = 2;
2434 return rc;
2437 static UINT ACTION_InstallFiles(MSIPACKAGE *package)
2439 UINT rc = ERROR_SUCCESS;
2440 INT index;
2441 MSIRECORD * uirow;
2442 WCHAR uipath[MAX_PATH];
2444 if (!package)
2445 return ERROR_INVALID_HANDLE;
2447 /* increment progress bar each time action data is sent */
2448 ui_progress(package,1,1,1,0);
2450 for (index = 0; index < package->loaded_files; index++)
2452 WCHAR path_to_source[MAX_PATH];
2453 MSIFILE *file;
2455 file = &package->files[index];
2457 if (file->Temporary)
2458 continue;
2460 if (!package->components[file->ComponentIndex].Enabled ||
2461 !package->components[file->ComponentIndex].FeatureState)
2463 TRACE("File %s is not scheduled for install\n",
2464 debugstr_w(file->File));
2465 continue;
2468 if ((file->State == 1) || (file->State == 2))
2470 TRACE("Installing %s\n",debugstr_w(file->File));
2471 rc = ready_media_for_file(package,file->Sequence,path_to_source);
2473 * WARNING!
2474 * our file table could change here because a new temp file
2475 * may have been created
2477 file = &package->files[index];
2478 if (rc != ERROR_SUCCESS)
2480 ERR("Unable to ready media\n");
2481 rc = ERROR_FUNCTION_FAILED;
2482 break;
2485 create_component_directory( package, file->ComponentIndex);
2487 strcpyW(file->SourcePath, path_to_source);
2488 strcatW(file->SourcePath, file->File);
2490 TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
2491 debugstr_w(file->TargetPath));
2493 /* the UI chunk */
2494 uirow=MSI_CreateRecord(9);
2495 MSI_RecordSetStringW(uirow,1,file->File);
2496 strcpyW(uipath,file->TargetPath);
2497 *(strrchrW(uipath,'\\')+1)=0;
2498 MSI_RecordSetStringW(uirow,9,uipath);
2499 MSI_RecordSetInteger(uirow,6,file->FileSize);
2500 ui_actiondata(package,szInstallFiles,uirow);
2501 msiobj_release( &uirow->hdr );
2503 rc = !MoveFileW(file->SourcePath,file->TargetPath);
2504 ui_progress(package,2,0,0,0);
2506 if (rc)
2508 ERR("Unable to move file (error %li)\n",GetLastError());
2509 rc = ERROR_SUCCESS;
2511 else
2512 file->State = 4;
2516 return rc;
2519 inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
2520 LPWSTR file_source)
2522 INT index;
2524 if (!package)
2525 return ERROR_INVALID_HANDLE;
2527 for (index = 0; index < package->loaded_files; index ++)
2529 if (strcmpW(file_key,package->files[index].File)==0)
2531 if (package->files[index].State >= 3)
2533 strcpyW(file_source,package->files[index].TargetPath);
2534 return ERROR_SUCCESS;
2536 else
2537 return ERROR_FILE_NOT_FOUND;
2541 return ERROR_FUNCTION_FAILED;
2544 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
2546 UINT rc;
2547 MSIQUERY * view;
2548 MSIRECORD * row = 0;
2549 static const WCHAR ExecSeqQuery[] = {
2550 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2551 'D','u','p','l','i','c','a','t','e','F','i','l','e',0};
2553 if (!package)
2554 return ERROR_INVALID_HANDLE;
2556 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2557 if (rc != ERROR_SUCCESS)
2558 return rc;
2560 rc = MSI_ViewExecute(view, 0);
2561 if (rc != ERROR_SUCCESS)
2563 MSI_ViewClose(view);
2564 msiobj_release(&view->hdr);
2565 return rc;
2568 while (1)
2570 WCHAR file_key[0x100];
2571 WCHAR file_source[MAX_PATH];
2572 WCHAR dest_name[0x100];
2573 WCHAR dest_path[MAX_PATH];
2574 WCHAR component[0x100];
2575 INT component_index;
2577 DWORD sz=0x100;
2579 rc = MSI_ViewFetch(view,&row);
2580 if (rc != ERROR_SUCCESS)
2582 rc = ERROR_SUCCESS;
2583 break;
2586 sz=0x100;
2587 rc = MSI_RecordGetStringW(row,2,component,&sz);
2588 if (rc != ERROR_SUCCESS)
2590 ERR("Unable to get component\n");
2591 msiobj_release(&row->hdr);
2592 break;
2595 component_index = get_loaded_component(package,component);
2596 if (!package->components[component_index].Enabled ||
2597 !package->components[component_index].FeatureState)
2599 TRACE("Skipping copy due to disabled component\n");
2600 msiobj_release(&row->hdr);
2601 continue;
2604 sz=0x100;
2605 rc = MSI_RecordGetStringW(row,3,file_key,&sz);
2606 if (rc != ERROR_SUCCESS)
2608 ERR("Unable to get file key\n");
2609 msiobj_release(&row->hdr);
2610 break;
2613 rc = get_file_target(package,file_key,file_source);
2615 if (rc != ERROR_SUCCESS)
2617 ERR("Original file unknown %s\n",debugstr_w(file_key));
2618 msiobj_release(&row->hdr);
2619 break;
2622 if (MSI_RecordIsNull(row,4))
2624 strcpyW(dest_name,strrchrW(file_source,'\\')+1);
2626 else
2628 sz=0x100;
2629 MSI_RecordGetStringW(row,4,dest_name,&sz);
2630 reduce_to_longfilename(dest_name);
2633 if (MSI_RecordIsNull(row,5))
2635 strcpyW(dest_path,file_source);
2636 *strrchrW(dest_path,'\\')=0;
2638 else
2640 WCHAR destkey[0x100];
2641 sz=0x100;
2642 MSI_RecordGetStringW(row,5,destkey,&sz);
2643 sz = 0x100;
2644 rc = resolve_folder(package, destkey, dest_path,FALSE,FALSE,NULL);
2645 if (rc != ERROR_SUCCESS)
2647 ERR("Unable to get destination folder\n");
2648 msiobj_release(&row->hdr);
2649 break;
2653 strcatW(dest_path,dest_name);
2655 TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
2656 debugstr_w(dest_path));
2658 if (strcmpW(file_source,dest_path))
2659 rc = !CopyFileW(file_source,dest_path,TRUE);
2660 else
2661 rc = ERROR_SUCCESS;
2663 if (rc != ERROR_SUCCESS)
2664 ERR("Failed to copy file\n");
2666 FIXME("We should track these duplicate files as well\n");
2668 msiobj_release(&row->hdr);
2670 MSI_ViewClose(view);
2671 msiobj_release(&view->hdr);
2672 return rc;
2677 /* OK this value is "interpretted" and then formatted based on the
2678 first few characters */
2679 static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type,
2680 DWORD *size)
2682 LPSTR data = NULL;
2683 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2685 if (value[1]=='x')
2687 LPWSTR ptr;
2688 CHAR byte[5];
2689 LPWSTR deformated;
2690 int count;
2692 deformat_string(package, &value[2], &deformated);
2694 /* binary value type */
2695 ptr = deformated;
2696 *type=REG_BINARY;
2697 *size = strlenW(ptr)/2;
2698 data = HeapAlloc(GetProcessHeap(),0,*size);
2700 byte[0] = '0';
2701 byte[1] = 'x';
2702 byte[4] = 0;
2703 count = 0;
2704 while (*ptr)
2706 byte[2]= *ptr;
2707 ptr++;
2708 byte[3]= *ptr;
2709 ptr++;
2710 data[count] = (BYTE)strtol(byte,NULL,0);
2711 count ++;
2713 HeapFree(GetProcessHeap(),0,deformated);
2715 TRACE("Data %li bytes(%i)\n",*size,count);
2717 else
2719 LPWSTR deformated;
2720 deformat_string(package, &value[1], &deformated);
2722 *type=REG_DWORD;
2723 *size = sizeof(DWORD);
2724 data = HeapAlloc(GetProcessHeap(),0,*size);
2725 *(LPDWORD)data = atoiW(deformated);
2726 TRACE("DWORD %i\n",*data);
2728 HeapFree(GetProcessHeap(),0,deformated);
2731 else
2733 WCHAR *ptr;
2734 *type=REG_SZ;
2736 if (value[0]=='#')
2738 if (value[1]=='%')
2740 ptr = &value[2];
2741 *type=REG_EXPAND_SZ;
2743 else
2744 ptr = &value[1];
2746 else
2747 ptr=value;
2749 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2751 return data;
2754 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2756 UINT rc;
2757 MSIQUERY * view;
2758 MSIRECORD * row = 0;
2759 static const WCHAR ExecSeqQuery[] = {
2760 's','e','l','e','c','t',' ','*',' ',
2761 'f','r','o','m',' ','R','e','g','i','s','t','r','y',0 };
2763 if (!package)
2764 return ERROR_INVALID_HANDLE;
2766 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2767 if (rc != ERROR_SUCCESS)
2768 return rc;
2770 rc = MSI_ViewExecute(view, 0);
2771 if (rc != ERROR_SUCCESS)
2773 MSI_ViewClose(view);
2774 msiobj_release(&view->hdr);
2775 return rc;
2778 /* increment progress bar each time action data is sent */
2779 ui_progress(package,1,1,1,0);
2781 while (1)
2783 static const WCHAR szHCR[] =
2784 {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T','\\',0};
2785 static const WCHAR szHCU[] =
2786 {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',0};
2787 static const WCHAR szHLM[] =
2788 {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',
2789 '\\',0};
2790 static const WCHAR szHU[] =
2791 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2793 WCHAR key[0x100];
2794 WCHAR name[0x100];
2795 LPWSTR value;
2796 LPSTR value_data = NULL;
2797 HKEY root_key, hkey;
2798 DWORD type,size;
2799 WCHAR component[0x100];
2800 INT component_index;
2801 MSIRECORD * uirow;
2802 WCHAR uikey[0x110];
2804 INT root;
2805 DWORD sz=0x100;
2807 rc = MSI_ViewFetch(view,&row);
2808 if (rc != ERROR_SUCCESS)
2810 rc = ERROR_SUCCESS;
2811 break;
2814 sz= 0x100;
2815 MSI_RecordGetStringW(row,6,component,&sz);
2816 component_index = get_loaded_component(package,component);
2818 if (!package->components[component_index].Enabled ||
2819 !package->components[component_index].FeatureState)
2821 TRACE("Skipping write due to disabled component\n");
2822 msiobj_release(&row->hdr);
2823 continue;
2826 /* null values have special meanings during uninstalls and such */
2828 if(MSI_RecordIsNull(row,5))
2830 msiobj_release(&row->hdr);
2831 continue;
2834 root = MSI_RecordGetInteger(row,2);
2835 sz = 0x100;
2836 MSI_RecordGetStringW(row,3,key,&sz);
2838 sz = 0x100;
2839 if (MSI_RecordIsNull(row,4))
2840 name[0]=0;
2841 else
2842 MSI_RecordGetStringW(row,4,name,&sz);
2844 /* get the root key */
2845 switch (root)
2847 case 0: root_key = HKEY_CLASSES_ROOT;
2848 strcpyW(uikey,szHCR); break;
2849 case 1: root_key = HKEY_CURRENT_USER;
2850 strcpyW(uikey,szHCU); break;
2851 case 2: root_key = HKEY_LOCAL_MACHINE;
2852 strcpyW(uikey,szHLM); break;
2853 case 3: root_key = HKEY_USERS;
2854 strcpyW(uikey,szHU); break;
2855 default:
2856 ERR("Unknown root %i\n",root);
2857 root_key=NULL;
2858 break;
2860 if (!root_key)
2862 msiobj_release(&row->hdr);
2863 continue;
2866 strcatW(uikey,key);
2867 if (RegCreateKeyW( root_key, key, &hkey))
2869 ERR("Could not create key %s\n",debugstr_w(key));
2870 msiobj_release(&row->hdr);
2871 continue;
2874 value = load_dynamic_stringW(row,5);
2875 value_data = parse_value(package, value, &type, &size);
2877 if (value_data)
2879 TRACE("Setting value %s\n",debugstr_w(name));
2880 RegSetValueExW(hkey, name, 0, type, value_data, size);
2882 uirow = MSI_CreateRecord(3);
2883 MSI_RecordSetStringW(uirow,2,name);
2884 MSI_RecordSetStringW(uirow,1,uikey);
2886 if (type == REG_SZ)
2887 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2888 else
2889 MSI_RecordSetStringW(uirow,3,value);
2891 ui_actiondata(package,szWriteRegistryValues,uirow);
2892 ui_progress(package,2,0,0,0);
2893 msiobj_release( &uirow->hdr );
2895 HeapFree(GetProcessHeap(),0,value_data);
2897 HeapFree(GetProcessHeap(),0,value);
2899 msiobj_release(&row->hdr);
2900 RegCloseKey(hkey);
2902 MSI_ViewClose(view);
2903 msiobj_release(&view->hdr);
2904 return rc;
2908 * This helper function should probably go alot of places
2910 * Thinking about this, maybe this should become yet another Bison file
2912 static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data)
2914 WCHAR* mark=NULL;
2915 DWORD size=0;
2916 DWORD chunk=0;
2917 WCHAR key[0x100];
2918 LPWSTR value;
2919 DWORD sz;
2920 UINT rc;
2922 /* scan for special characters */
2923 if (!strchrW(ptr,'[') || (strchrW(ptr,'[') && !strchrW(ptr,']')))
2925 /* not formatted */
2926 size = (strlenW(ptr)+1) * sizeof(WCHAR);
2927 *data = HeapAlloc(GetProcessHeap(),0,size);
2928 strcpyW(*data,ptr);
2929 return size;
2932 /* formatted string located */
2933 mark = strchrW(ptr,'[');
2934 if (mark != ptr)
2936 INT cnt = (mark - ptr);
2937 TRACE("%i (%i) characters before marker\n",cnt,(mark-ptr));
2938 size = cnt * sizeof(WCHAR);
2939 size += sizeof(WCHAR);
2940 *data = HeapAlloc(GetProcessHeap(),0,size);
2941 strncpyW(*data,ptr,cnt);
2942 (*data)[cnt]=0;
2944 else
2946 size = sizeof(WCHAR);
2947 *data = HeapAlloc(GetProcessHeap(),0,size);
2948 (*data)[0]=0;
2950 mark++;
2951 strcpyW(key,mark);
2952 *strchrW(key,']')=0;
2953 mark = strchrW(mark,']');
2954 mark++;
2955 TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
2956 sz = 0;
2957 rc = MSI_GetPropertyW(package, key, NULL, &sz);
2958 if ((rc == ERROR_SUCCESS) || (rc == ERROR_MORE_DATA))
2960 LPWSTR newdata;
2962 sz++;
2963 value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
2964 MSI_GetPropertyW(package, key, value, &sz);
2966 chunk = (strlenW(value)+1) * sizeof(WCHAR);
2967 size+=chunk;
2968 newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
2969 *data = newdata;
2970 strcatW(*data,value);
2972 TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
2973 if (*mark!=0)
2975 LPWSTR newdata;
2976 chunk = (strlenW(mark)+1) * sizeof(WCHAR);
2977 size+=chunk;
2978 newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
2979 *data = newdata;
2980 strcatW(*data,mark);
2982 (*data)[strlenW(*data)]=0;
2983 TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
2985 /* recursively do this to clean up */
2986 mark = HeapAlloc(GetProcessHeap(),0,size);
2987 strcpyW(mark,*data);
2988 TRACE("String at this point %s\n",debugstr_w(mark));
2989 size = deformat_string(package,mark,data);
2990 HeapFree(GetProcessHeap(),0,mark);
2991 return size;
2994 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2996 WCHAR level[10000];
2997 INT install_level;
2998 DWORD sz;
2999 INT i,j;
3000 DWORD rc;
3001 LPWSTR override = NULL;
3002 static const WCHAR addlocal[]={'A','D','D','L','O','C','A','L',0};
3003 static const WCHAR all[]={'A','L','L',0};
3004 static const WCHAR szlevel[] = {
3005 'I','N','S','T','A','L','L','L','E','V','E','L',0};
3006 static const WCHAR szAddLocal[] = {
3007 'A','D','D','L','O','C','A','L',0};
3009 /* I do not know if this is where it should happen.. but */
3011 TRACE("Checking Install Level\n");
3013 sz = 10000;
3014 if (MSI_GetPropertyW(package,szlevel,level,&sz)==ERROR_SUCCESS)
3015 install_level = atoiW(level);
3016 else
3017 install_level = 1;
3019 sz = 0;
3020 rc = MSI_GetPropertyW(package,szAddLocal,NULL,&sz);
3021 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
3023 sz++;
3024 override = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
3025 MSI_GetPropertyW(package, addlocal,override,&sz);
3029 * components FeatureState defaults to FALSE. the idea is we want to
3030 * enable the component is ANY feature that uses it is enabled to install
3032 for(i = 0; i < package->loaded_features; i++)
3034 BOOL feature_state= ((package->features[i].Level > 0) &&
3035 (package->features[i].Level <= install_level));
3037 if (override && (strcmpiW(override,all)==0 ||
3038 strstrW(override,package->features[i].Feature)))
3040 TRACE("Override of install level found\n");
3041 feature_state = TRUE;
3042 package->features[i].Enabled = feature_state;
3045 TRACE("Feature %s has a state of %i\n",
3046 debugstr_w(package->features[i].Feature), feature_state);
3047 for( j = 0; j < package->features[i].ComponentCount; j++)
3049 package->components[package->features[i].Components[j]].FeatureState
3050 |= feature_state;
3053 if (override != NULL)
3054 HeapFree(GetProcessHeap(),0,override);
3056 * so basically we ONLY want to install a component if its Enabled AND
3057 * FeatureState are both TRUE
3059 return ERROR_SUCCESS;
3062 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3064 DWORD progress = 0;
3065 static const WCHAR q1[]={
3066 'S','E','L','E','C','T',' ','*',' ',
3067 'F','R','O','M',' ','R','e','g','i','s','t','r','y',0};
3068 UINT rc;
3069 MSIQUERY * view;
3070 MSIRECORD * row = 0;
3072 TRACE(" InstallValidate \n");
3074 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3075 if (rc != ERROR_SUCCESS)
3076 return rc;
3077 rc = MSI_ViewExecute(view, 0);
3078 if (rc != ERROR_SUCCESS)
3080 MSI_ViewClose(view);
3081 msiobj_release(&view->hdr);
3082 return rc;
3084 while (1)
3086 rc = MSI_ViewFetch(view,&row);
3087 if (rc != ERROR_SUCCESS)
3089 rc = ERROR_SUCCESS;
3090 break;
3092 progress +=1;
3094 msiobj_release(&row->hdr);
3096 MSI_ViewClose(view);
3097 msiobj_release(&view->hdr);
3099 ui_progress(package,0,progress+package->loaded_files,0,0);
3101 return ERROR_SUCCESS;
3104 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3106 UINT rc;
3107 MSIQUERY * view;
3108 MSIRECORD * row = 0;
3109 static const WCHAR ExecSeqQuery[] = {
3110 'S','E','L','E','C','T',' ','*',' ',
3111 'f','r','o','m',' ','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n',0};
3112 static const WCHAR title[]=
3113 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3115 TRACE("Checking launch conditions\n");
3117 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3118 if (rc != ERROR_SUCCESS)
3119 return rc;
3121 rc = MSI_ViewExecute(view, 0);
3122 if (rc != ERROR_SUCCESS)
3124 MSI_ViewClose(view);
3125 msiobj_release(&view->hdr);
3126 return rc;
3129 rc = ERROR_SUCCESS;
3130 while (rc == ERROR_SUCCESS)
3132 LPWSTR cond = NULL;
3133 LPWSTR message = NULL;
3135 rc = MSI_ViewFetch(view,&row);
3136 if (rc != ERROR_SUCCESS)
3138 rc = ERROR_SUCCESS;
3139 break;
3142 cond = load_dynamic_stringW(row,1);
3144 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
3146 message = load_dynamic_stringW(row,2);
3147 MessageBoxW(NULL,message,title,MB_OK);
3148 HeapFree(GetProcessHeap(),0,message);
3149 rc = ERROR_FUNCTION_FAILED;
3151 HeapFree(GetProcessHeap(),0,cond);
3152 msiobj_release(&row->hdr);
3154 MSI_ViewClose(view);
3155 msiobj_release(&view->hdr);
3156 return rc;
3159 static void resolve_keypath( MSIPACKAGE* package, INT
3160 component_index, WCHAR *keypath)
3162 MSICOMPONENT* cmp = &package->components[component_index];
3164 if (cmp->KeyPath[0]==0)
3166 resolve_folder(package,cmp->Directory,keypath,FALSE,FALSE,NULL);
3167 return;
3169 if ((cmp->Attributes & 0x4) || (cmp->Attributes & 0x20))
3171 FIXME("UNIMPLEMENTED keypath as Registry or ODBC Source\n");
3172 keypath[0]=0;
3174 else
3176 int j;
3177 j = get_loaded_file(package,cmp->KeyPath);
3179 if (j>=0)
3180 strcpyW(keypath,package->files[j].TargetPath);
3185 * Ok further analysis makes me think that this work is
3186 * actually done in the PublishComponents and PublishFeatures
3187 * step, and not here. It appears like the keypath and all that is
3188 * resolved in this step, however actually written in the Publish steps.
3189 * But we will leave it here for now because it is unclear
3191 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3193 WCHAR productcode[0x100];
3194 WCHAR squished_pc[0x100];
3195 WCHAR squished_cc[0x100];
3196 DWORD sz;
3197 UINT rc;
3198 INT i;
3199 HKEY hkey=0,hkey2=0,hkey3=0;
3200 static const WCHAR szProductCode[]=
3201 {'P','r','o','d','u','c','t','C','o','d','e',0};
3202 static const WCHAR szInstaller[] = {
3203 'S','o','f','t','w','a','r','e','\\',
3204 'M','i','c','r','o','s','o','f','t','\\',
3205 'W','i','n','d','o','w','s','\\',
3206 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3207 'I','n','s','t','a','l','l','e','r',0 };
3208 static const WCHAR szFeatures[] = {
3209 'F','e','a','t','u','r','e','s',0 };
3210 static const WCHAR szComponents[] = {
3211 'C','o','m','p','o','n','e','n','t','s',0 };
3213 if (!package)
3214 return ERROR_INVALID_HANDLE;
3216 /* writes the Component and Features values to the registry */
3217 sz = 0x100;
3218 rc = MSI_GetPropertyW(package,szProductCode,productcode,&sz);
3219 if (rc != ERROR_SUCCESS)
3220 return ERROR_SUCCESS;
3222 squash_guid(productcode,squished_pc);
3223 rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller,&hkey);
3224 if (rc != ERROR_SUCCESS)
3225 goto end;
3227 rc = RegCreateKeyW(hkey,szFeatures,&hkey2);
3228 if (rc != ERROR_SUCCESS)
3229 goto end;
3231 rc = RegCreateKeyW(hkey2,squished_pc,&hkey3);
3232 if (rc != ERROR_SUCCESS)
3233 goto end;
3235 /* here the guids are base 85 encoded */
3236 for (i = 0; i < package->loaded_features; i++)
3238 LPWSTR data = NULL;
3239 GUID clsid;
3240 int j;
3241 INT size;
3243 size = package->features[i].ComponentCount*21*sizeof(WCHAR);
3244 data = HeapAlloc(GetProcessHeap(), 0, size);
3246 data[0] = 0;
3247 for (j = 0; j < package->features[i].ComponentCount; j++)
3249 WCHAR buf[21];
3250 TRACE("From %s\n",debugstr_w(package->components
3251 [package->features[i].Components[j]].ComponentId));
3252 CLSIDFromString(package->components
3253 [package->features[i].Components[j]].ComponentId,
3254 &clsid);
3255 encode_base85_guid(&clsid,buf);
3256 TRACE("to %s\n",debugstr_w(buf));
3257 strcatW(data,buf);
3260 size = strlenW(data)*sizeof(WCHAR);
3261 RegSetValueExW(hkey3,package->features[i].Feature,0,REG_SZ,
3262 (LPSTR)data,size);
3263 HeapFree(GetProcessHeap(),0,data);
3266 RegCloseKey(hkey3);
3267 RegCloseKey(hkey2);
3269 rc = RegCreateKeyW(hkey,szComponents,&hkey2);
3270 if (rc != ERROR_SUCCESS)
3271 goto end;
3273 for (i = 0; i < package->loaded_components; i++)
3275 if (package->components[i].ComponentId[0]!=0)
3277 WCHAR keypath[0x1000];
3278 MSIRECORD * uirow;
3280 squash_guid(package->components[i].ComponentId,squished_cc);
3281 rc = RegCreateKeyW(hkey2,squished_cc,&hkey3);
3282 if (rc != ERROR_SUCCESS)
3283 continue;
3285 resolve_keypath(package,i,keypath);
3287 RegSetValueExW(hkey3,squished_pc,0,REG_SZ,(LPVOID)keypath,
3288 (strlenW(keypath)+1)*sizeof(WCHAR));
3289 RegCloseKey(hkey3);
3291 /* UI stuff */
3292 uirow = MSI_CreateRecord(3);
3293 MSI_RecordSetStringW(uirow,1,productcode);
3294 MSI_RecordSetStringW(uirow,2,package->components[i].ComponentId);
3295 MSI_RecordSetStringW(uirow,3,keypath);
3296 ui_actiondata(package,szProcessComponents,uirow);
3297 msiobj_release( &uirow->hdr );
3300 end:
3301 RegCloseKey(hkey2);
3302 RegCloseKey(hkey);
3303 return rc;
3306 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3309 * ok this is a bit confusting.. I am given a _Component key and i believe
3310 * that the file that is being registered as a type library is the "key file
3311 * of that component" which i interpert to mean "The file in the KeyPath of
3312 * that component"
3314 UINT rc;
3315 MSIQUERY * view;
3316 MSIRECORD * row = 0;
3317 static const WCHAR Query[] = {
3318 'S','E','L','E','C','T',' ','*',' ',
3319 'f','r','o','m',' ','T','y','p','e','L','i','b',0};
3320 ITypeLib *ptLib;
3321 HRESULT res;
3323 if (!package)
3324 return ERROR_INVALID_HANDLE;
3326 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3327 if (rc != ERROR_SUCCESS)
3328 return rc;
3330 rc = MSI_ViewExecute(view, 0);
3331 if (rc != ERROR_SUCCESS)
3333 MSI_ViewClose(view);
3334 msiobj_release(&view->hdr);
3335 return rc;
3338 while (1)
3340 WCHAR component[0x100];
3341 DWORD sz;
3342 INT index;
3344 rc = MSI_ViewFetch(view,&row);
3345 if (rc != ERROR_SUCCESS)
3347 rc = ERROR_SUCCESS;
3348 break;
3351 sz = 0x100;
3352 MSI_RecordGetStringW(row,3,component,&sz);
3354 index = get_loaded_component(package,component);
3355 if (index < 0)
3357 msiobj_release(&row->hdr);
3358 continue;
3361 if (!package->components[index].Enabled ||
3362 !package->components[index].FeatureState)
3364 TRACE("Skipping typelib reg due to disabled component\n");
3365 msiobj_release(&row->hdr);
3366 continue;
3369 index = get_loaded_file(package,package->components[index].KeyPath);
3371 if (index < 0)
3373 msiobj_release(&row->hdr);
3374 continue;
3377 res = LoadTypeLib(package->files[index].TargetPath,&ptLib);
3378 if (SUCCEEDED(res))
3380 WCHAR help[MAX_PATH];
3381 WCHAR helpid[0x100];
3383 sz = 0x100;
3384 MSI_RecordGetStringW(row,6,helpid,&sz);
3386 resolve_folder(package,helpid,help,FALSE,FALSE,NULL);
3388 res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help);
3389 if (!SUCCEEDED(res))
3390 ERR("Failed to register type library %s\n",
3391 debugstr_w(package->files[index].TargetPath));
3392 else
3394 /* yes the row has more fields than i need, but #1 is
3395 correct and the only one i need. why make a new row */
3397 ui_actiondata(package,szRegisterTypeLibraries,row);
3399 TRACE("Registered %s\n",
3400 debugstr_w(package->files[index].TargetPath));
3403 if (ptLib)
3404 ITypeLib_Release(ptLib);
3406 else
3407 ERR("Failed to load type library %s\n",
3408 debugstr_w(package->files[index].TargetPath));
3410 msiobj_release(&row->hdr);
3412 MSI_ViewClose(view);
3413 msiobj_release(&view->hdr);
3414 return rc;
3418 static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
3420 static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
3421 UINT rc;
3422 MSIQUERY * view;
3423 MSIRECORD * row = 0;
3424 static const WCHAR ExecSeqQuery[] =
3425 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'
3426 ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};
3427 WCHAR Query[0x1000];
3428 HKEY hkey2,hkey3;
3429 LPWSTR buffer=0;
3431 if (!package)
3432 return ERROR_INVALID_HANDLE;
3434 sprintfW(Query,ExecSeqQuery,clsid);
3436 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3437 if (rc != ERROR_SUCCESS)
3438 return rc;
3440 rc = MSI_ViewExecute(view, 0);
3441 if (rc != ERROR_SUCCESS)
3443 MSI_ViewClose(view);
3444 msiobj_release(&view->hdr);
3445 return rc;
3448 RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
3449 RegCreateKeyW(hkey2,clsid,&hkey3);
3450 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
3451 (strlenW(app)+1)*sizeof(WCHAR));
3453 rc = MSI_ViewFetch(view,&row);
3454 if (rc != ERROR_SUCCESS)
3456 MSI_ViewClose(view);
3457 msiobj_release(&view->hdr);
3458 return rc;
3461 if (!MSI_RecordIsNull(row,2))
3463 LPWSTR deformated=0;
3464 UINT size;
3465 static const WCHAR szRemoteServerName[] =
3466 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
3467 buffer = load_dynamic_stringW(row,2);
3468 size = deformat_string(package,buffer,&deformated);
3469 RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated,
3470 size);
3471 HeapFree(GetProcessHeap(),0,deformated);
3472 HeapFree(GetProcessHeap(),0,buffer);
3475 if (!MSI_RecordIsNull(row,3))
3477 static const WCHAR szLocalService[] =
3478 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
3479 UINT size;
3480 buffer = load_dynamic_stringW(row,3);
3481 size = (strlenW(buffer)+1) * sizeof(WCHAR);
3482 RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size);
3483 HeapFree(GetProcessHeap(),0,buffer);
3486 if (!MSI_RecordIsNull(row,4))
3488 static const WCHAR szService[] =
3489 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
3490 UINT size;
3491 buffer = load_dynamic_stringW(row,4);
3492 size = (strlenW(buffer)+1) * sizeof(WCHAR);
3493 RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size);
3494 HeapFree(GetProcessHeap(),0,buffer);
3497 if (!MSI_RecordIsNull(row,5))
3499 static const WCHAR szDLL[] =
3500 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
3501 UINT size;
3502 buffer = load_dynamic_stringW(row,5);
3503 size = (strlenW(buffer)+1) * sizeof(WCHAR);
3504 RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size);
3505 HeapFree(GetProcessHeap(),0,buffer);
3508 if (!MSI_RecordIsNull(row,6))
3510 static const WCHAR szActivate[] =
3511 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
3512 static const WCHAR szY[] = {'Y',0};
3514 if (MSI_RecordGetInteger(row,6))
3515 RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
3518 if (!MSI_RecordIsNull(row,7))
3520 static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
3521 static const WCHAR szUser[] =
3522 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
3524 if (MSI_RecordGetInteger(row,7))
3525 RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34);
3528 msiobj_release(&row->hdr);
3529 MSI_ViewClose(view);
3530 msiobj_release(&view->hdr);
3531 RegCloseKey(hkey3);
3532 RegCloseKey(hkey2);
3533 return rc;
3536 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
3539 * Again I am assuming the words, "Whose key file respesents" when refering
3540 * to a Component as to mean the Components KeyPath file
3542 * Also there is a very strong connection between ClassInfo and ProgID
3543 * that I am mostly glossing over.
3544 * What would be more propper is to load the ClassInfo and the ProgID info
3545 * into memory data structures and then be able to enable and disable them
3546 * based on component.
3549 UINT rc;
3550 MSIQUERY * view;
3551 MSIRECORD * row = 0;
3552 static const WCHAR ExecSeqQuery[] = {
3553 'S','E','L','E','C','T',' ','*',' ',
3554 'f','r','o','m',' ','C','l','a','s','s',0};
3555 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
3556 static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
3557 static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
3558 HKEY hkey,hkey2,hkey3;
3560 if (!package)
3561 return ERROR_INVALID_HANDLE;
3563 rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
3564 if (rc != ERROR_SUCCESS)
3565 return ERROR_FUNCTION_FAILED;
3567 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3568 if (rc != ERROR_SUCCESS)
3569 goto end;
3571 rc = MSI_ViewExecute(view, 0);
3572 if (rc != ERROR_SUCCESS)
3574 MSI_ViewClose(view);
3575 msiobj_release(&view->hdr);
3576 goto end;
3579 while (1)
3581 WCHAR clsid[0x100];
3582 WCHAR buffer[0x100];
3583 WCHAR desc[0x100];
3584 DWORD sz;
3585 INT index;
3587 rc = MSI_ViewFetch(view,&row);
3588 if (rc != ERROR_SUCCESS)
3590 rc = ERROR_SUCCESS;
3591 break;
3594 sz=0x100;
3595 MSI_RecordGetStringW(row,3,buffer,&sz);
3597 index = get_loaded_component(package,buffer);
3599 if (index < 0)
3601 msiobj_release(&row->hdr);
3602 continue;
3605 if (!package->components[index].Enabled ||
3606 !package->components[index].FeatureState)
3608 TRACE("Skipping class reg due to disabled component\n");
3609 msiobj_release(&row->hdr);
3610 continue;
3613 sz=0x100;
3614 MSI_RecordGetStringW(row,1,clsid,&sz);
3615 RegCreateKeyW(hkey,clsid,&hkey2);
3617 if (!MSI_RecordIsNull(row,5))
3619 sz=0x100;
3620 MSI_RecordGetStringW(row,5,desc,&sz);
3622 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc,
3623 (strlenW(desc)+1)*sizeof(WCHAR));
3625 else
3626 desc[0]=0;
3628 sz=0x100;
3629 MSI_RecordGetStringW(row,2,buffer,&sz);
3631 RegCreateKeyW(hkey2,buffer,&hkey3);
3633 index = get_loaded_file(package,package->components[index].KeyPath);
3634 RegSetValueExW(hkey3,NULL,0,REG_SZ,
3635 (LPVOID)package->files[index].TargetPath,
3636 (strlenW(package->files[index].TargetPath)+1)
3637 *sizeof(WCHAR));
3639 RegCloseKey(hkey3);
3641 if (!MSI_RecordIsNull(row,4))
3643 sz=0x100;
3644 MSI_RecordGetStringW(row,4,buffer,&sz);
3646 RegCreateKeyW(hkey2,szProgID,&hkey3);
3648 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer,
3649 (strlenW(buffer)+1)*sizeof(WCHAR));
3651 RegCloseKey(hkey3);
3654 if (!MSI_RecordIsNull(row,6))
3656 sz=0x100;
3657 MSI_RecordGetStringW(row,6,buffer,&sz);
3659 RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer,
3660 (strlenW(buffer)+1)*sizeof(WCHAR));
3662 register_appid(package,buffer,desc);
3665 RegCloseKey(hkey2);
3667 FIXME("Process the rest of the fields >7\n");
3669 ui_actiondata(package,szRegisterClassInfo,row);
3671 msiobj_release(&row->hdr);
3673 MSI_ViewClose(view);
3674 msiobj_release(&view->hdr);
3676 end:
3677 RegCloseKey(hkey);
3678 return rc;
3681 static UINT register_progid_base(MSIRECORD * row, LPWSTR clsid)
3683 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
3684 HKEY hkey,hkey2;
3685 WCHAR buffer[0x100];
3686 DWORD sz;
3689 sz = 0x100;
3690 MSI_RecordGetStringW(row,1,buffer,&sz);
3691 RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
3693 if (!MSI_RecordIsNull(row,4))
3695 sz = 0x100;
3696 MSI_RecordGetStringW(row,4,buffer,&sz);
3697 RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
3698 sizeof(WCHAR));
3701 if (!MSI_RecordIsNull(row,3))
3703 sz = 0x100;
3705 MSI_RecordGetStringW(row,3,buffer,&sz);
3706 RegCreateKeyW(hkey,szCLSID,&hkey2);
3707 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
3708 sizeof(WCHAR));
3710 if (clsid)
3711 strcpyW(clsid,buffer);
3713 RegCloseKey(hkey2);
3715 else
3717 FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
3718 return ERROR_FUNCTION_FAILED;
3720 if (!MSI_RecordIsNull(row,5))
3721 FIXME ("UNHANDLED icon in Progid\n");
3722 return ERROR_SUCCESS;
3725 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid);
3727 static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent,
3728 LPWSTR clsid)
3730 UINT rc;
3731 MSIQUERY * view;
3732 MSIRECORD * row = 0;
3733 static const WCHAR Query_t[] =
3734 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'
3735 ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'
3736 ,'%','s','`',0};
3737 WCHAR Query[0x1000];
3739 if (!package)
3740 return ERROR_INVALID_HANDLE;
3742 sprintfW(Query,Query_t,parent);
3744 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3745 if (rc != ERROR_SUCCESS)
3746 return rc;
3748 rc = MSI_ViewExecute(view, 0);
3749 if (rc != ERROR_SUCCESS)
3751 MSI_ViewClose(view);
3752 msiobj_release(&view->hdr);
3753 return rc;
3756 rc = MSI_ViewFetch(view,&row);
3757 if (rc != ERROR_SUCCESS)
3759 MSI_ViewClose(view);
3760 msiobj_release(&view->hdr);
3761 return rc;
3764 register_progid(package,row,clsid);
3766 msiobj_release(&row->hdr);
3767 MSI_ViewClose(view);
3768 msiobj_release(&view->hdr);
3769 return rc;
3772 static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid)
3774 UINT rc = ERROR_SUCCESS;
3776 if (MSI_RecordIsNull(row,2))
3777 rc = register_progid_base(row,clsid);
3778 else
3780 WCHAR buffer[0x1000];
3781 DWORD sz;
3782 HKEY hkey,hkey2;
3783 static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
3785 sz = 0x100;
3786 MSI_RecordGetStringW(row,2,buffer,&sz);
3787 rc = register_parent_progid(package,buffer,clsid);
3789 sz = 0x100;
3790 MSI_RecordGetStringW(row,1,buffer,&sz);
3791 RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
3792 /* clasid is same as parent */
3793 RegCreateKeyW(hkey,szCLSID,&hkey2);
3794 RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
3795 sizeof(WCHAR));
3797 RegCloseKey(hkey2);
3798 if (!MSI_RecordIsNull(row,4))
3800 sz = 0x100;
3801 MSI_RecordGetStringW(row,4,buffer,&sz);
3802 RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer,
3803 (strlenW(buffer)+1) * sizeof(WCHAR));
3806 if (!MSI_RecordIsNull(row,5))
3807 FIXME ("UNHANDLED icon in Progid\n");
3809 RegCloseKey(hkey);
3811 return rc;
3814 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
3817 * Sigh, here i am just brute force registering all progid
3818 * this needs to be linked to the Classes that have been registerd
3819 * but the easiest way to do that is to load all these stuff into
3820 * memory for easy checking.
3822 * gives me something to continue to work toward
3824 UINT rc;
3825 MSIQUERY * view;
3826 MSIRECORD * row = 0;
3827 static const WCHAR Query[] = {
3828 'S','E','L','E','C','T',' ','*',' ',
3829 'F','R','O','M',' ','P','r','o','g','I','d',0};
3831 if (!package)
3832 return ERROR_INVALID_HANDLE;
3834 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3835 if (rc != ERROR_SUCCESS)
3836 return rc;
3838 rc = MSI_ViewExecute(view, 0);
3839 if (rc != ERROR_SUCCESS)
3841 MSI_ViewClose(view);
3842 msiobj_release(&view->hdr);
3843 return rc;
3846 while (1)
3848 WCHAR clsid[0x1000];
3850 rc = MSI_ViewFetch(view,&row);
3851 if (rc != ERROR_SUCCESS)
3853 rc = ERROR_SUCCESS;
3854 break;
3857 register_progid(package,row,clsid);
3858 ui_actiondata(package,szRegisterProgIdInfo,row);
3860 msiobj_release(&row->hdr);
3862 MSI_ViewClose(view);
3863 msiobj_release(&view->hdr);
3864 return rc;
3867 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name,
3868 LPWSTR FilePath)
3870 WCHAR ProductCode[0x100];
3871 WCHAR SystemFolder[MAX_PATH];
3872 DWORD sz;
3874 static const WCHAR szInstaller[] =
3875 {'I','n','s','t','a','l','l','e','r','\\',0};
3876 static const WCHAR szProductCode[] =
3877 {'P','r','o','d','u','c','t','C','o','d','e',0};
3878 static const WCHAR szFolder[] =
3879 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3881 sz = 0x100;
3882 MSI_GetPropertyW(package,szProductCode,ProductCode,&sz);
3883 if (strlenW(ProductCode)==0)
3884 return ERROR_FUNCTION_FAILED;
3886 sz = MAX_PATH;
3887 MSI_GetPropertyW(package,szFolder,SystemFolder,&sz);
3888 strcatW(SystemFolder,szInstaller);
3889 strcatW(SystemFolder,ProductCode);
3890 create_full_pathW(SystemFolder);
3892 strcpyW(FilePath,SystemFolder);
3893 strcatW(FilePath,cszbs);
3894 strcatW(FilePath,icon_name);
3895 return ERROR_SUCCESS;
3898 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3900 UINT rc;
3901 MSIQUERY * view;
3902 MSIRECORD * row = 0;
3903 static const WCHAR Query[] = {
3904 'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ',
3905 'S','h','o','r','t','c','u','t',0};
3906 IShellLinkW *sl;
3907 IPersistFile *pf;
3908 HRESULT res;
3910 if (!package)
3911 return ERROR_INVALID_HANDLE;
3913 res = CoInitialize( NULL );
3914 if (FAILED (res))
3916 ERR("CoInitialize failed\n");
3917 return ERROR_FUNCTION_FAILED;
3920 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3921 if (rc != ERROR_SUCCESS)
3922 return rc;
3924 rc = MSI_ViewExecute(view, 0);
3925 if (rc != ERROR_SUCCESS)
3927 MSI_ViewClose(view);
3928 msiobj_release(&view->hdr);
3929 return rc;
3932 while (1)
3934 WCHAR target_file[MAX_PATH];
3935 WCHAR buffer[0x100];
3936 DWORD sz;
3937 DWORD index;
3938 static const WCHAR szlnk[]={'.','l','n','k',0};
3940 rc = MSI_ViewFetch(view,&row);
3941 if (rc != ERROR_SUCCESS)
3943 rc = ERROR_SUCCESS;
3944 break;
3947 sz = 0x100;
3948 MSI_RecordGetStringW(row,4,buffer,&sz);
3950 index = get_loaded_component(package,buffer);
3952 if (index < 0)
3954 msiobj_release(&row->hdr);
3955 continue;
3958 if (!package->components[index].Enabled ||
3959 !package->components[index].FeatureState)
3961 TRACE("Skipping shortcut creation due to disabled component\n");
3962 msiobj_release(&row->hdr);
3963 continue;
3966 ui_actiondata(package,szCreateShortcuts,row);
3968 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3969 &IID_IShellLinkW, (LPVOID *) &sl );
3971 if (FAILED(res))
3973 ERR("Is IID_IShellLink\n");
3974 msiobj_release(&row->hdr);
3975 continue;
3978 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3979 if( FAILED( res ) )
3981 ERR("Is IID_IPersistFile\n");
3982 msiobj_release(&row->hdr);
3983 continue;
3986 sz = 0x100;
3987 MSI_RecordGetStringW(row,2,buffer,&sz);
3988 resolve_folder(package, buffer,target_file,FALSE,FALSE,NULL);
3990 sz = 0x100;
3991 MSI_RecordGetStringW(row,3,buffer,&sz);
3992 reduce_to_longfilename(buffer);
3993 strcatW(target_file,buffer);
3994 if (!strchrW(target_file,'.'))
3995 strcatW(target_file,szlnk);
3997 sz = 0x100;
3998 MSI_RecordGetStringW(row,5,buffer,&sz);
3999 if (strchrW(buffer,'['))
4001 LPWSTR deformated;
4002 deformat_string(package,buffer,&deformated);
4003 IShellLinkW_SetPath(sl,deformated);
4004 HeapFree(GetProcessHeap(),0,deformated);
4006 else
4008 FIXME("UNHANDLED shortcut format, advertised shortcut\n");
4009 IPersistFile_Release( pf );
4010 IShellLinkW_Release( sl );
4011 msiobj_release(&row->hdr);
4012 continue;
4015 if (!MSI_RecordIsNull(row,6))
4017 LPWSTR deformated;
4018 sz = 0x100;
4019 MSI_RecordGetStringW(row,6,buffer,&sz);
4020 deformat_string(package,buffer,&deformated);
4021 IShellLinkW_SetArguments(sl,deformated);
4022 HeapFree(GetProcessHeap(),0,deformated);
4025 if (!MSI_RecordIsNull(row,7))
4027 LPWSTR deformated;
4028 deformated = load_dynamic_stringW(row,7);
4029 IShellLinkW_SetDescription(sl,deformated);
4030 HeapFree(GetProcessHeap(),0,deformated);
4033 if (!MSI_RecordIsNull(row,8))
4034 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
4036 if (!MSI_RecordIsNull(row,9))
4038 WCHAR Path[MAX_PATH];
4039 INT index;
4041 sz = 0x100;
4042 MSI_RecordGetStringW(row,9,buffer,&sz);
4044 build_icon_path(package,buffer,Path);
4045 index = MSI_RecordGetInteger(row,10);
4047 IShellLinkW_SetIconLocation(sl,Path,index);
4050 if (!MSI_RecordIsNull(row,11))
4051 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
4053 if (!MSI_RecordIsNull(row,12))
4055 WCHAR Path[MAX_PATH];
4057 sz = 0x100;
4058 MSI_RecordGetStringW(row,12,buffer,&sz);
4059 resolve_folder(package, buffer, Path, FALSE, FALSE, NULL);
4060 IShellLinkW_SetWorkingDirectory(sl,Path);
4063 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
4064 IPersistFile_Save(pf,target_file,FALSE);
4066 IPersistFile_Release( pf );
4067 IShellLinkW_Release( sl );
4069 msiobj_release(&row->hdr);
4071 MSI_ViewClose(view);
4072 msiobj_release(&view->hdr);
4075 CoUninitialize();
4077 return rc;
4082 * 99% of the work done here is only done for
4083 * advertised installs. However this is where the
4084 * Icon table is processed and written out
4085 * so that is waht I am going to do here.
4087 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4089 UINT rc;
4090 MSIQUERY * view;
4091 MSIRECORD * row = 0;
4092 static const WCHAR Query[]={
4093 'S','E','L','E','C','T',' ','*',' ',
4094 'f','r','o','m',' ','I','c','o','n',0};
4095 DWORD sz;
4097 if (!package)
4098 return ERROR_INVALID_HANDLE;
4100 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4101 if (rc != ERROR_SUCCESS)
4102 return rc;
4104 rc = MSI_ViewExecute(view, 0);
4105 if (rc != ERROR_SUCCESS)
4107 MSI_ViewClose(view);
4108 msiobj_release(&view->hdr);
4109 return rc;
4112 while (1)
4114 HANDLE the_file;
4115 WCHAR FilePath[MAX_PATH];
4116 WCHAR FileName[MAX_PATH];
4117 CHAR buffer[1024];
4119 rc = MSI_ViewFetch(view,&row);
4120 if (rc != ERROR_SUCCESS)
4122 rc = ERROR_SUCCESS;
4123 break;
4126 sz = MAX_PATH;
4127 MSI_RecordGetStringW(row,1,FileName,&sz);
4128 if (sz == 0)
4130 ERR("Unable to get FileName\n");
4131 msiobj_release(&row->hdr);
4132 continue;
4135 build_icon_path(package,FileName,FilePath);
4137 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
4139 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
4140 FILE_ATTRIBUTE_NORMAL, NULL);
4142 if (the_file == INVALID_HANDLE_VALUE)
4144 ERR("Unable to create file %s\n",debugstr_w(FilePath));
4145 msiobj_release(&row->hdr);
4146 continue;
4151 DWORD write;
4152 sz = 1024;
4153 rc = MSI_RecordReadStream(row,2,buffer,&sz);
4154 if (rc != ERROR_SUCCESS)
4156 ERR("Failed to get stream\n");
4157 CloseHandle(the_file);
4158 DeleteFileW(FilePath);
4159 break;
4161 WriteFile(the_file,buffer,sz,&write,NULL);
4162 } while (sz == 1024);
4164 CloseHandle(the_file);
4165 msiobj_release(&row->hdr);
4167 MSI_ViewClose(view);
4168 msiobj_release(&view->hdr);
4169 return rc;
4173 /* Msi functions that seem appropriate here */
4174 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
4176 LPWSTR szwAction;
4177 UINT rc;
4179 TRACE(" exteral attempt at action %s\n",szAction);
4181 if (!szAction)
4182 return ERROR_FUNCTION_FAILED;
4183 if (hInstall == 0)
4184 return ERROR_FUNCTION_FAILED;
4186 szwAction = strdupAtoW(szAction);
4188 if (!szwAction)
4189 return ERROR_FUNCTION_FAILED;
4192 rc = MsiDoActionW(hInstall, szwAction);
4193 HeapFree(GetProcessHeap(),0,szwAction);
4194 return rc;
4197 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
4199 MSIPACKAGE *package;
4200 UINT ret = ERROR_INVALID_HANDLE;
4202 TRACE(" external attempt at action %s \n",debugstr_w(szAction));
4204 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4205 if( package )
4207 ret = ACTION_PerformAction(package,szAction);
4208 msiobj_release( &package->hdr );
4210 return ret;
4213 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
4214 LPSTR szPathBuf, DWORD* pcchPathBuf)
4216 LPWSTR szwFolder;
4217 LPWSTR szwPathBuf;
4218 UINT rc;
4220 TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
4222 if (!szFolder)
4223 return ERROR_FUNCTION_FAILED;
4224 if (hInstall == 0)
4225 return ERROR_FUNCTION_FAILED;
4227 szwFolder = strdupAtoW(szFolder);
4229 if (!szwFolder)
4230 return ERROR_FUNCTION_FAILED;
4232 szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
4234 rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
4236 WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
4237 *pcchPathBuf, NULL, NULL );
4239 HeapFree(GetProcessHeap(),0,szwFolder);
4240 HeapFree(GetProcessHeap(),0,szwPathBuf);
4242 return rc;
4245 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
4246 szPathBuf, DWORD* pcchPathBuf)
4248 WCHAR path[MAX_PATH];
4249 UINT rc;
4250 MSIPACKAGE *package;
4252 TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
4254 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4255 if( !package )
4256 return ERROR_INVALID_HANDLE;
4257 rc = resolve_folder(package, szFolder, path, FALSE, FALSE, NULL);
4258 msiobj_release( &package->hdr );
4260 if (rc == ERROR_SUCCESS && strlenW(path) > *pcchPathBuf)
4262 *pcchPathBuf = strlenW(path)+1;
4263 return ERROR_MORE_DATA;
4265 else if (rc == ERROR_SUCCESS)
4267 *pcchPathBuf = strlenW(path)+1;
4268 strcpyW(szPathBuf,path);
4269 TRACE("Returning Path %s\n",debugstr_w(path));
4272 return rc;
4276 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder,
4277 LPSTR szPathBuf, DWORD* pcchPathBuf)
4279 LPWSTR szwFolder;
4280 LPWSTR szwPathBuf;
4281 UINT rc;
4283 TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
4285 if (!szFolder)
4286 return ERROR_FUNCTION_FAILED;
4287 if (hInstall == 0)
4288 return ERROR_FUNCTION_FAILED;
4290 szwFolder = strdupAtoW(szFolder);
4291 if (!szwFolder)
4292 return ERROR_FUNCTION_FAILED;
4294 szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
4296 rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
4298 WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
4299 *pcchPathBuf, NULL, NULL );
4301 HeapFree(GetProcessHeap(),0,szwFolder);
4302 HeapFree(GetProcessHeap(),0,szwPathBuf);
4304 return rc;
4307 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
4308 szPathBuf, DWORD* pcchPathBuf)
4310 WCHAR path[MAX_PATH];
4311 UINT rc;
4312 MSIPACKAGE *package;
4314 TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
4316 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4317 if( !package )
4318 return ERROR_INVALID_HANDLE;
4319 rc = resolve_folder(package, szFolder, path, TRUE, FALSE, NULL);
4320 msiobj_release( &package->hdr );
4322 if (rc == ERROR_SUCCESS && strlenW(path) > *pcchPathBuf)
4324 *pcchPathBuf = strlenW(path)+1;
4325 return ERROR_MORE_DATA;
4327 else if (rc == ERROR_SUCCESS)
4329 *pcchPathBuf = strlenW(path)+1;
4330 strcpyW(szPathBuf,path);
4331 TRACE("Returning Path %s\n",debugstr_w(path));
4334 return rc;
4338 UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder,
4339 LPCSTR szFolderPath)
4341 LPWSTR szwFolder;
4342 LPWSTR szwFolderPath;
4343 UINT rc;
4345 if (!szFolder)
4346 return ERROR_FUNCTION_FAILED;
4347 if (hInstall == 0)
4348 return ERROR_FUNCTION_FAILED;
4350 szwFolder = strdupAtoW(szFolder);
4351 if (!szwFolder)
4352 return ERROR_FUNCTION_FAILED;
4354 szwFolderPath = strdupAtoW(szFolderPath);
4355 if (!szwFolderPath)
4357 HeapFree(GetProcessHeap(),0,szwFolder);
4358 return ERROR_FUNCTION_FAILED;
4361 rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
4363 HeapFree(GetProcessHeap(),0,szwFolder);
4364 HeapFree(GetProcessHeap(),0,szwFolderPath);
4366 return rc;
4369 UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
4370 LPCWSTR szFolderPath)
4372 INT i;
4373 WCHAR path[MAX_PATH];
4374 MSIFOLDER *folder;
4376 TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
4378 if (package==NULL)
4379 return ERROR_INVALID_HANDLE;
4381 if (szFolderPath[0]==0)
4382 return ERROR_FUNCTION_FAILED;
4384 if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)
4385 return ERROR_FUNCTION_FAILED;
4387 resolve_folder(package,szFolder,path,FALSE,FALSE,&folder);
4389 if (!folder)
4390 return ERROR_INVALID_PARAMETER;
4392 strcpyW(folder->Property,szFolderPath);
4394 for (i = 0; i < package->loaded_folders; i++)
4395 package->folders[i].ResolvedTarget[0]=0;
4397 for (i = 0; i < package->loaded_folders; i++)
4398 resolve_folder(package, package->folders[i].Directory, path, FALSE,
4399 TRUE, NULL);
4401 return ERROR_SUCCESS;
4404 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
4405 LPCWSTR szFolderPath)
4407 MSIPACKAGE *package;
4408 UINT ret;
4410 TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
4412 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4413 ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
4414 msiobj_release( &package->hdr );
4415 return ret;
4418 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, DWORD iRunMode)
4420 FIXME("STUB (%li)\n",iRunMode);
4421 return FALSE;
4425 * according to the docs when this is called it immediently recalculates all the
4426 * components states as well
4428 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
4429 INSTALLSTATE iState)
4431 LPWSTR szwFeature = NULL;
4432 UINT rc;
4434 szwFeature = strdupAtoW(szFeature);
4436 if (!szwFeature)
4437 return ERROR_FUNCTION_FAILED;
4439 rc = MsiSetFeatureStateW(hInstall,szwFeature, iState);
4441 HeapFree(GetProcessHeap(),0,szwFeature);
4443 return rc;
4446 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
4447 INSTALLSTATE iState)
4449 MSIPACKAGE* package;
4450 INT index;
4452 TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
4454 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4455 if (!package)
4456 return ERROR_INVALID_HANDLE;
4458 index = get_loaded_feature(package,szFeature);
4459 if (index < 0)
4460 return ERROR_UNKNOWN_FEATURE;
4462 package->features[index].State = iState;
4464 return ERROR_SUCCESS;
4467 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
4468 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4470 LPWSTR szwFeature = NULL;
4471 UINT rc;
4473 szwFeature = strdupAtoW(szFeature);
4475 rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
4477 HeapFree( GetProcessHeap(), 0 , szwFeature);
4479 return rc;
4482 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
4483 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4485 INT index;
4487 index = get_loaded_feature(package,szFeature);
4488 if (index < 0)
4489 return ERROR_UNKNOWN_FEATURE;
4491 if (piInstalled)
4492 *piInstalled = package->features[index].State;
4494 if (piAction)
4496 if (package->features[index].Enabled)
4497 *piAction = INSTALLSTATE_LOCAL;
4498 else
4499 *piAction = INSTALLSTATE_UNKNOWN;
4502 return ERROR_SUCCESS;
4505 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
4506 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4508 MSIPACKAGE* package;
4509 UINT ret;
4511 TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
4512 piAction);
4514 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4515 if (!package)
4516 return ERROR_INVALID_HANDLE;
4517 ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
4518 msiobj_release( &package->hdr );
4519 return ret;
4522 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
4523 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4525 LPWSTR szwComponent= NULL;
4526 UINT rc;
4528 szwComponent= strdupAtoW(szComponent);
4530 rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
4532 HeapFree( GetProcessHeap(), 0 , szwComponent);
4534 return rc;
4537 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
4538 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4540 INT index;
4542 TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
4543 piAction);
4545 index = get_loaded_component(package,szComponent);
4546 if (index < 0)
4547 return ERROR_UNKNOWN_COMPONENT;
4549 if (piInstalled)
4550 *piInstalled = package->components[index].State;
4552 if (piAction)
4554 if (package->components[index].Enabled &&
4555 package->components[index].FeatureState)
4556 *piAction = INSTALLSTATE_LOCAL;
4557 else
4558 *piAction = INSTALLSTATE_UNKNOWN;
4561 return ERROR_SUCCESS;
4564 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
4565 INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
4567 MSIPACKAGE* package;
4568 UINT ret;
4570 TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
4571 piInstalled, piAction);
4573 package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
4574 if (!package)
4575 return ERROR_INVALID_HANDLE;
4576 ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
4577 msiobj_release( &package->hdr );
4578 return ret;
4581 #if 0
4582 static UINT ACTION_Template(MSIPACKAGE *package)
4584 UINT rc;
4585 MSIQUERY * view;
4586 MSIRECORD * row = 0;
4587 static const WCHAR ExecSeqQuery[] = {0};
4589 rc = MsiDatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4590 if (rc != ERROR_SUCCESS)
4591 return rc;
4593 rc = MsiViewExecute(view, 0);
4594 if (rc != ERROR_SUCCESS)
4596 MsiViewClose(view);
4597 msiobj_release(&view->hdr);
4598 return rc;
4601 while (1)
4603 rc = MsiViewFetch(view,&row);
4604 if (rc != ERROR_SUCCESS)
4606 rc = ERROR_SUCCESS;
4607 break;
4610 msiobj_release(&row->hdr);
4612 MsiViewClose(view);
4613 msiobj_release(&view->hdr);
4614 return rc;
4616 #endif