2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
36 #include "wine/debug.h"
45 #include "wine/unicode.h"
48 #define CUSTOM_ACTION_TYPE_MASK 0x3F
50 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
52 typedef struct tagMSIFEATURE
55 WCHAR Feature_Parent
[96];
57 WCHAR Description
[0x100];
66 INT Components
[1024]; /* yes hardcoded limit.... I am bad */
70 typedef struct tagMSICOMPONENT
73 WCHAR ComponentId
[96];
76 WCHAR Condition
[0x100];
85 typedef struct tagMSIFOLDER
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 */
96 /* 0 = uninitialized */
98 /* 2 = created remove if empty */
99 /* 3 = created persist if empty */
104 typedef struct tagMSIFILE
108 WCHAR FileName
[MAX_PATH
];
116 /* 0 = uninitialize */
117 /* 1 = not present */
118 /* 2 = present but replace */
119 /* 3 = present do not replace */
121 WCHAR SourcePath
[MAX_PATH
];
122 WCHAR TargetPath
[MAX_PATH
];
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',
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
)
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
);
236 inline static WCHAR
*strdupAtoW( const char *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
);
248 inline static WCHAR
*load_dynamic_stringW(MSIRECORD
*row
, INT index
)
255 rc
= MSI_RecordGetStringW(row
,index
,NULL
,&sz
);
260 ret
= HeapAlloc(GetProcessHeap(),0,sz
* sizeof (WCHAR
));
261 rc
= MSI_RecordGetStringW(row
,index
,ret
,&sz
);
265 inline static int get_loaded_component(MSIPACKAGE
* package
, LPCWSTR Component
)
270 for (i
= 0; i
< package
->loaded_components
; i
++)
272 if (strcmpW(Component
,package
->components
[i
].Component
)==0)
281 inline static int get_loaded_feature(MSIPACKAGE
* package
, LPCWSTR Feature
)
286 for (i
= 0; i
< package
->loaded_features
; i
++)
288 if (strcmpW(Feature
,package
->features
[i
].Feature
)==0)
297 inline static int get_loaded_file(MSIPACKAGE
* package
, LPCWSTR file
)
302 for (i
= 0; i
< package
->loaded_files
; i
++)
304 if (strcmpW(file
,package
->files
[i
].File
)==0)
313 static UINT
track_tempfile(MSIPACKAGE
*package
, LPCWSTR name
, LPCWSTR path
)
321 for (i
=0; i
< package
->loaded_files
; i
++)
322 if (strcmpW(package
->files
[i
].File
,name
)==0)
325 index
= package
->loaded_files
;
326 package
->loaded_files
++;
327 if (package
->loaded_files
== 1)
328 package
->files
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE
));
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
));
344 void ACTION_remove_tracked_tempfiles(MSIPACKAGE
* package
)
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
)
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};
382 static WCHAR
*ActionFormat
=NULL
;
383 static WCHAR LastAction
[0x100] = {0};
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
)
393 rc
= MSI_ViewExecute(view
, 0);
394 if (rc
!= ERROR_SUCCESS
)
399 rc
= MSI_ViewFetch(view
,&row
);
400 if (rc
!= ERROR_SUCCESS
)
406 if (MSI_RecordIsNull(row
,3))
408 msiobj_release(&row
->hdr
);
410 msiobj_release(&view
->hdr
);
415 HeapFree(GetProcessHeap(),0,ActionFormat
);
417 ActionFormat
= load_dynamic_stringW(row
,3);
418 strcpyW(LastAction
,action
);
419 msiobj_release(&row
->hdr
);
421 msiobj_release(&view
->hdr
);
433 ptr2
= strchrW(ptr
,'[');
436 strncpyW(tmp
,ptr
,ptr2
-ptr
);
438 strcatW(message
,tmp
);
441 data
= load_dynamic_stringW(record
,field
);
444 strcatW(message
,data
);
445 HeapFree(GetProcessHeap(),0,data
);
447 ptr
=strchrW(ptr2
,']');
452 strcatW(message
,ptr
);
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};
480 WCHAR
*ActionText
=NULL
;
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
)
489 rc
= MSI_ViewExecute(view
, 0);
490 if (rc
!= ERROR_SUCCESS
)
493 msiobj_release(&view
->hdr
);
496 rc
= MSI_ViewFetch(view
,&row
);
497 if (rc
!= ERROR_SUCCESS
)
500 msiobj_release(&view
->hdr
);
504 ActionText
= load_dynamic_stringW(row
,2);
505 msiobj_release(&row
->hdr
);
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
,
523 static const WCHAR template_s
[]=
524 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ','%','s',
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};
534 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
536 sprintfW(message
,template_s
,timet
,action
);
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
)
557 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
562 WCHAR check
[MAX_PATH
];
566 strcpyW(pth
,szPackagePath
);
567 p
= strrchrW(pth
,'\\');
575 if (MSI_GetPropertyW(package
,cszSourceDir
,check
,&size
)
577 MSI_SetPropertyW(package
, cszSourceDir
, pth
);
583 ptr
= (LPWSTR
)szCommandLine
;
590 TRACE("Looking at %s\n",debugstr_w(ptr
));
592 ptr2
= strchrW(ptr
,'=');
597 strncpyW(prop
,ptr
,ptr2
-ptr
);
602 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
615 strncpyW(val
,ptr2
,len
);
621 TRACE("Found commandline property (%s) = (%s)\n", debugstr_w(prop
),
623 MSI_SetPropertyW(package
,prop
,val
);
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
);
637 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
640 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
646 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
650 static const WCHAR ExecSeqQuery
[] = {
651 's','e','l','e','c','t',' ','*',' ',
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 };
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','`',
672 rc
= MSI_DatabaseOpenViewW(package
->db
, IVQuery
, &view
);
673 if (rc
!= ERROR_SUCCESS
)
675 rc
= MSI_ViewExecute(view
, 0);
676 if (rc
!= ERROR_SUCCESS
)
679 msiobj_release(&view
->hdr
);
682 rc
= MSI_ViewFetch(view
,&row
);
683 if (rc
!= ERROR_SUCCESS
)
686 msiobj_release(&view
->hdr
);
689 seq
= MSI_RecordGetInteger(row
,1);
690 msiobj_release(&row
->hdr
);
692 msiobj_release(&view
->hdr
);
693 sprintfW(Query
,ExecSeqQuery
,seq
);
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
)
706 msiobj_release(&view
->hdr
);
710 TRACE("Running the actions \n");
717 rc
= MSI_ViewFetch(view
,&row
);
718 if (rc
!= ERROR_SUCCESS
)
724 /* check conditions */
725 if (!MSI_RecordIsNull(row
,2))
728 cond
= load_dynamic_stringW(row
,2);
732 /* this is a hack to skip errors in the condition code */
733 if (MSI_EvaluateConditionW(package
, cond
) ==
736 HeapFree(GetProcessHeap(),0,cond
);
737 msiobj_release(&row
->hdr
);
741 HeapFree(GetProcessHeap(),0,cond
);
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
);
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
);
763 msiobj_release(&row
->hdr
);
767 msiobj_release(&view
->hdr
);
775 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
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
)
795 msiobj_release(&view
->hdr
);
799 TRACE("Running the actions \n");
807 rc
= MSI_ViewFetch(view
,&row
);
808 if (rc
!= ERROR_SUCCESS
)
814 /* check conditions */
815 if (!MSI_RecordIsNull(row
,2))
818 cond
= load_dynamic_stringW(row
,2);
822 /* this is a hack to skip errors in the condition code */
823 if (MSI_EvaluateConditionW(package
, cond
) ==
826 HeapFree(GetProcessHeap(),0,cond
);
827 msiobj_release(&row
->hdr
);
831 HeapFree(GetProcessHeap(),0,cond
);
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
);
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
);
853 msiobj_release(&row
->hdr
);
857 msiobj_release(&view
->hdr
);
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
);
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)
928 else if ((rc
= ACTION_CustomAction(package
,action
)) != ERROR_SUCCESS
)
930 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action
));
934 ui_actioninfo(package
, action
, FALSE
, rc
);
939 static UINT
ACTION_CustomAction(MSIPACKAGE
*package
,const WCHAR
*action
)
941 UINT rc
= ERROR_SUCCESS
;
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};
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
)
962 rc
= MSI_ViewExecute(view
, 0);
963 if (rc
!= ERROR_SUCCESS
)
966 msiobj_release(&view
->hdr
);
970 rc
= MSI_ViewFetch(view
,&row
);
971 if (rc
!= ERROR_SUCCESS
)
974 msiobj_release(&view
->hdr
);
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
);
992 case 2: /* EXE file stored in a Binary table strem */
993 rc
= HANDLE_CustomType2(package
,source
,target
,type
);
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
);
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
);
1015 static UINT
store_binary_to_temp(MSIPACKAGE
*package
, const LPWSTR source
,
1020 if (MSI_GetPropertyW(package
, cszTempFolder
, tmp_file
, &sz
)
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
;
1033 /* write out the file */
1036 MSIRECORD
* row
= 0;
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};
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
);
1056 rc
= MSI_DatabaseOpenViewW( package
->db
, Query
, &view
);
1057 if (rc
!= ERROR_SUCCESS
)
1060 rc
= MSI_ViewExecute(view
, 0);
1061 if (rc
!= ERROR_SUCCESS
)
1063 MSI_ViewClose(view
);
1064 msiobj_release(&view
->hdr
);
1068 rc
= MSI_ViewFetch(view
,&row
);
1069 if (rc
!= ERROR_SUCCESS
)
1071 MSI_ViewClose(view
);
1072 msiobj_release(&view
->hdr
);
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
);
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
);
1105 MSIPACKAGE
*package
;
1106 WCHAR target
[MAX_PATH
];
1107 WCHAR source
[MAX_PATH
];
1111 static DWORD WINAPI
DllThread(LPVOID info
)
1115 thread_struct
*stuff
;
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
);
1126 proc
= strdupWtoA( stuff
->target
);
1127 fn
= (CustomEntry
*)GetProcAddress(DLL
,proc
);
1131 MSIPACKAGE
*package
= stuff
->package
;
1133 TRACE("Calling function\n");
1134 hPackage
= msiobj_findhandle( &package
->hdr
);
1136 ERR("Handle for object %p not found\n", package
);
1138 msiobj_release( &package
->hdr
);
1141 ERR("Cannot load functon\n");
1143 HeapFree(GetProcessHeap(),0,proc
);
1147 ERR("Unable to load library\n");
1148 msiobj_release( &stuff
->package
->hdr
);
1149 HeapFree( GetProcessHeap(), 0, info
);
1154 static UINT
HANDLE_CustomType1(MSIPACKAGE
*package
, const LPWSTR source
,
1155 const LPWSTR target
, const INT type
)
1157 WCHAR tmp_file
[MAX_PATH
];
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
);
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
);
1193 proc
= strdupWtoA( target
);
1194 fn
= (CustomEntry
*)GetProcAddress(DLL
,proc
);
1199 TRACE("Calling function\n");
1200 hPackage
= msiobj_findhandle( &package
->hdr
);
1202 ERR("Handle for object %p not found\n", package
);
1204 msiobj_release( &package
->hdr
);
1207 ERR("Cannot load functon\n");
1209 HeapFree(GetProcessHeap(),0,proc
);
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];
1223 PROCESS_INFORMATION info
;
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
);
1246 ERR("Unable to execute command\n");
1247 return ERROR_SUCCESS
;
1251 WaitForSingleObject(info
.hProcess
,INFINITE
);
1253 return ERROR_SUCCESS
;
1256 /***********************************************************************
1259 * Recursively create all directories in the path.
1261 * shamelessly stolen from setupapi/queue.c
1263 static BOOL
create_full_pathW(const WCHAR
*path
)
1269 new_path
= HeapAlloc(GetProcessHeap(), 0, (strlenW(path
) + 1) *
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
))
1279 DWORD last_error
= GetLastError();
1280 if(last_error
== ERROR_ALREADY_EXISTS
)
1283 if(last_error
!= ERROR_PATH_NOT_FOUND
)
1289 if(!(slash
= strrchrW(new_path
, '\\')))
1295 len
= slash
- new_path
;
1297 if(!create_full_pathW(new_path
))
1302 new_path
[len
] = '\\';
1305 HeapFree(GetProcessHeap(), 0, new_path
);
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 };
1322 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1323 if (rc
!= ERROR_SUCCESS
)
1326 rc
= MSI_ViewExecute(view
, 0);
1327 if (rc
!= ERROR_SUCCESS
)
1329 MSI_ViewClose(view
);
1330 msiobj_release(&view
->hdr
);
1337 WCHAR full_path
[MAX_PATH
];
1339 MSIRECORD
*row
= NULL
, *uirow
;
1341 rc
= MSI_ViewFetch(view
,&row
);
1342 if (rc
!= ERROR_SUCCESS
)
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
);
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
);
1368 TRACE("Folder is %s\n",debugstr_w(full_path
));
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
);
1381 msiobj_release(&row
->hdr
);
1383 MSI_ViewClose(view
);
1384 msiobj_release(&view
->hdr
);
1389 static int load_component(MSIPACKAGE
* package
, MSIRECORD
* row
)
1391 int index
= package
->loaded_components
;
1394 /* fill in the data */
1396 package
->loaded_components
++;
1397 if (package
->loaded_components
== 1)
1398 package
->components
= HeapAlloc(GetProcessHeap(),0,
1399 sizeof(MSICOMPONENT
));
1401 package
->components
= HeapReAlloc(GetProcessHeap(),0,
1402 package
->components
, package
->loaded_components
*
1403 sizeof(MSICOMPONENT
));
1405 memset(&package
->components
[index
],0,sizeof(MSICOMPONENT
));
1408 MSI_RecordGetStringW(row
,1,package
->components
[index
].Component
,&sz
);
1410 TRACE("Loading Component %s\n",
1411 debugstr_w(package
->components
[index
].Component
));
1414 if (!MSI_RecordIsNull(row
,2))
1415 MSI_RecordGetStringW(row
,2,package
->components
[index
].ComponentId
,&sz
);
1418 MSI_RecordGetStringW(row
,3,package
->components
[index
].Directory
,&sz
);
1420 package
->components
[index
].Attributes
= MSI_RecordGetInteger(row
,4);
1423 MSI_RecordGetStringW(row
,5,package
->components
[index
].Condition
,&sz
);
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
;
1435 static void load_feature(MSIPACKAGE
* package
, MSIRECORD
* row
)
1437 int index
= package
->loaded_features
;
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};
1453 /* fill in the data */
1455 package
->loaded_features
++;
1456 if (package
->loaded_features
== 1)
1457 package
->features
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE
));
1459 package
->features
= HeapReAlloc(GetProcessHeap(),0,package
->features
,
1460 package
->loaded_features
* sizeof(MSIFEATURE
));
1462 memset(&package
->features
[index
],0,sizeof(MSIFEATURE
));
1465 MSI_RecordGetStringW(row
,1,package
->features
[index
].Feature
,&sz
);
1467 TRACE("Loading feature %s\n",debugstr_w(package
->features
[index
].Feature
));
1470 if (!MSI_RecordIsNull(row
,2))
1471 MSI_RecordGetStringW(row
,2,package
->features
[index
].Feature_Parent
,&sz
);
1474 if (!MSI_RecordIsNull(row
,3))
1475 MSI_RecordGetStringW(row
,3,package
->features
[index
].Title
,&sz
);
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);
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
)
1499 rc
= MSI_ViewExecute(view
,0);
1500 if (rc
!= ERROR_SUCCESS
)
1502 MSI_ViewClose(view
);
1503 msiobj_release(&view
->hdr
);
1509 WCHAR buffer
[0x100];
1512 INT cnt
= package
->features
[index
].ComponentCount
;
1514 rc
= MSI_ViewFetch(view
,&row2
);
1515 if (rc
!= ERROR_SUCCESS
)
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
);
1525 TRACE("Component %s already loaded at %i\n", debugstr_w(buffer
),
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
);
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
);
1551 rc
= MSI_ViewFetch(view2
,&row3
);
1552 if (rc
!= ERROR_SUCCESS
)
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
1581 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
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
);
1598 rc
= MSI_DatabaseOpenViewW(package
->db
,Query_all
,&view
);
1599 if (rc
!= ERROR_SUCCESS
)
1601 rc
= MSI_ViewExecute(view
,0);
1602 if (rc
!= ERROR_SUCCESS
)
1604 MSI_ViewClose(view
);
1605 msiobj_release(&view
->hdr
);
1612 rc
= MSI_ViewFetch(view
,&row
);
1613 if (rc
!= ERROR_SUCCESS
)
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
;
1629 WCHAR buffer
[0x100];
1632 /* fill in the data */
1634 package
->loaded_files
++;
1635 if (package
->loaded_files
== 1)
1636 package
->files
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE
));
1638 package
->files
= HeapReAlloc(GetProcessHeap(),0,
1639 package
->files
, package
->loaded_files
* sizeof(MSIFILE
));
1641 memset(&package
->files
[index
],0,sizeof(MSIFILE
));
1644 MSI_RecordGetStringW(row
,1,package
->files
[index
].File
,&sz
);
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
;
1656 if (package
->files
[index
].ComponentIndex
== -1)
1657 ERR("Unfound Component %s\n",debugstr_w(buffer
));
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);
1667 if (!MSI_RecordIsNull(row
,5))
1668 MSI_RecordGetStringW(row
,5,package
->files
[index
].Version
,&sz
);
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
)
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};
1698 return ERROR_INVALID_HANDLE
;
1700 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1701 if (rc
!= ERROR_SUCCESS
)
1704 rc
= MSI_ViewExecute(view
, 0);
1705 if (rc
!= ERROR_SUCCESS
)
1707 MSI_ViewClose(view
);
1708 msiobj_release(&view
->hdr
);
1714 rc
= MSI_ViewFetch(view
,&row
);
1715 if (rc
!= ERROR_SUCCESS
)
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
)
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};
1739 WCHAR targetbuffer
[0x100];
1740 WCHAR
*srcdir
= NULL
;
1741 WCHAR
*targetdir
= NULL
;
1742 WCHAR parent
[0x100];
1744 MSIRECORD
* row
= 0;
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
);
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,
1767 package
->folders
= HeapReAlloc(GetProcessHeap(),0,
1768 package
->folders
, package
->loaded_folders
*
1771 memset(&package
->folders
[index
],0,sizeof(MSIFOLDER
));
1773 strcpyW(package
->folders
[index
].Directory
,dir
);
1778 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1780 if (rc
!= ERROR_SUCCESS
)
1783 rc
= MSI_ViewExecute(view
, 0);
1784 if (rc
!= ERROR_SUCCESS
)
1786 MSI_ViewClose(view
);
1787 msiobj_release(&view
->hdr
);
1791 rc
= MSI_ViewFetch(view
,&row
);
1792 if (rc
!= ERROR_SUCCESS
)
1794 MSI_ViewClose(view
);
1795 msiobj_release(&view
->hdr
);
1800 MSI_RecordGetStringW(row
,3,targetbuffer
,&sz
);
1801 targetdir
=targetbuffer
;
1803 /* split src and target dir */
1804 if (strchrW(targetdir
,':'))
1806 srcdir
=strchrW(targetdir
,':');
1813 /* for now only pick long filename versions */
1814 if (strchrW(targetdir
,'|'))
1816 targetdir
= strchrW(targetdir
,'|');
1820 if (srcdir
&& strchrW(srcdir
,'|'))
1822 srcdir
= strchrW(srcdir
,'|');
1827 /* now check for root dirs */
1828 if (targetdir
[0] == '.' && targetdir
[1] == 0)
1831 if (srcdir
&& srcdir
[0] == '.' && srcdir
[1] == 0)
1835 strcpyW(package
->folders
[index
].TargetDefault
,targetdir
);
1838 strcpyW(package
->folders
[index
].SourceDefault
,srcdir
);
1840 strcpyW(package
->folders
[index
].SourceDefault
,targetdir
);
1842 if (MSI_RecordIsNull(row
,2))
1847 MSI_RecordGetStringW(row
,2,parent
,&sz
);
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
));
1860 package
->folders
[index
].ParentIndex
= -2;
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
);
1874 static UINT
resolve_folder(MSIPACKAGE
*package
, LPCWSTR name
, LPWSTR path
,
1875 BOOL source
, BOOL set_prop
, MSIFOLDER
**folder
)
1878 UINT rc
= ERROR_SUCCESS
;
1881 TRACE("Working to resolve %s\n",debugstr_w(name
));
1886 /* special resolving for Target and Source root dir */
1887 if (strcmpW(name
,cszTargetDir
)==0 || strcmpW(name
,cszSourceDir
)==0)
1892 rc
= MSI_GetPropertyW(package
,cszTargetDir
,path
,&sz
);
1893 if (rc
!= ERROR_SUCCESS
)
1896 rc
= MSI_GetPropertyW(package
,cszRootDrive
,path
,&sz
);
1898 MSI_SetPropertyW(package
,cszTargetDir
,path
);
1901 *folder
= &(package
->folders
[0]);
1907 rc
= MSI_GetPropertyW(package
,cszSourceDir
,path
,&sz
);
1908 if (rc
!= ERROR_SUCCESS
)
1911 rc
= MSI_GetPropertyW(package
,cszDatabase
,path
,&sz
);
1912 if (rc
== ERROR_SUCCESS
)
1914 LPWSTR ptr
= strrchrW(path
,'\\');
1923 *folder
= &(package
->folders
[0]);
1928 for (i
= 0; i
< package
->loaded_folders
; i
++)
1930 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
1934 if (i
>= package
->loaded_folders
)
1935 return ERROR_FUNCTION_FAILED
;
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
));
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
,
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
));
1978 MSI_SetPropertyW(package
,name
,path
);
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
);
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 };
2014 TRACE("Building Directory properties\n");
2016 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2017 if (rc
!= ERROR_SUCCESS
)
2020 rc
= MSI_ViewExecute(view
, 0);
2021 if (rc
!= ERROR_SUCCESS
)
2023 MSI_ViewClose(view
);
2024 msiobj_release(&view
->hdr
);
2031 WCHAR path
[MAX_PATH
];
2032 MSIRECORD
* row
= 0;
2035 rc
= MSI_ViewFetch(view
,&row
);
2036 if (rc
!= ERROR_SUCCESS
)
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
];
2069 /* calculate target */
2070 resolve_folder(package
, comp
->Directory
, file
->TargetPath
, FALSE
,
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
)
2080 comp
->Cost
+= file
->FileSize
;
2084 if (file
->Version
[0])
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
);
2101 VerQueryValueW(version
,name
,(LPVOID
)filever
,&sz
);
2102 HeapFree(GetProcessHeap(),0,version
);
2104 if (strcmpW(version
,file
->Version
)<0)
2107 FIXME("cost should be diff in size\n");
2108 comp
->Cost
+= file
->FileSize
;
2119 TRACE("Evaluating Condition Table\n");
2121 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
2122 if (rc
!= ERROR_SUCCESS
)
2125 rc
= MSI_ViewExecute(view
, 0);
2126 if (rc
!= ERROR_SUCCESS
)
2128 MSI_ViewClose(view
);
2129 msiobj_release(&view
->hdr
);
2135 WCHAR Feature
[0x100];
2136 MSIRECORD
* row
= 0;
2140 rc
= MSI_ViewFetch(view
,&row
);
2142 if (rc
!= ERROR_SUCCESS
)
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
));
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
),
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
,
2204 WCHAR tmp
[MAX_PATH
];
2206 rc
= read_raw_stream_data(package
->db
,stream_name
,&data
,&size
);
2207 if (rc
!= ERROR_SUCCESS
)
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
;
2226 WriteFile(the_file
,data
,size
,&write
,NULL
);
2227 CloseHandle(the_file
);
2228 TRACE("wrote %li bytes to %s\n",write
,debugstr_w(source
));
2230 HeapFree(GetProcessHeap(),0,data
);
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
,
2245 static HMODULE advpack
;
2247 char *cab_path
, *cab_file
;
2251 if (!advpack
&& !(advpack
= LoadLibraryA( "advpack.dll" )))
2253 ERR( "could not load advpack.dll\n" );
2256 if (!(pExtractFiles
= (void *)GetProcAddress( advpack
, "ExtractFiles"
2259 ERR( "could not find ExtractFiles in advpack.dll\n" );
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
);
2274 static BOOL
extract_cabinet_file_cabinet( const WCHAR
*cabinet
,
2278 /* from cabinet.h */
2280 struct ExtractFileList
{
2282 struct ExtractFileList
*next
;
2283 BOOL unknown
; /* always 1L */
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 */
2296 HRESULT WINAPI
Extract(EXTRACTdest
*dest
, LPCSTR what
);
2298 char *cab_path
, *src_path
;
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
);
2308 fl
.filename
= cab_path
;
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
);
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
);
2328 static UINT
ready_media_for_file(MSIPACKAGE
*package
, UINT sequence
,
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};
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
)
2358 rc
= MSI_ViewExecute(view
, 0);
2359 if (rc
!= ERROR_SUCCESS
)
2361 MSI_ViewClose(view
);
2362 msiobj_release(&view
->hdr
);
2366 rc
= MSI_ViewFetch(view
,&row
);
2367 if (rc
!= ERROR_SUCCESS
)
2369 MSI_ViewClose(view
);
2370 msiobj_release(&view
->hdr
);
2373 seq
= MSI_RecordGetInteger(row
,2);
2374 last_sequence
= seq
;
2376 if (!MSI_RecordIsNull(row
,4))
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 */
2384 writeout_cabinet_stream(package
,&cab
[1],source
);
2385 strcpyW(path
,source
);
2386 *(strrchrW(path
,'\\')+1)=0;
2391 if (MSI_GetPropertyW(package
, cszSourceDir
, source
, &sz
))
2393 ERR("No Source dir defined \n");
2394 rc
= ERROR_FUNCTION_FAILED
;
2398 strcpyW(path
,source
);
2399 strcatW(source
,cab
);
2400 /* extract the cab file into a folder in the temp folder */
2402 if (MSI_GetPropertyW(package
, cszTempFolder
,path
, &sz
)
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
);
2415 inline static UINT
create_component_directory ( MSIPACKAGE
* package
, INT component
)
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
)
2427 /* create the path */
2428 if (folder
->State
== 0)
2430 create_full_pathW(install_path
);
2437 static UINT
ACTION_InstallFiles(MSIPACKAGE
*package
)
2439 UINT rc
= ERROR_SUCCESS
;
2442 WCHAR uipath
[MAX_PATH
];
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
];
2455 file
= &package
->files
[index
];
2457 if (file
->Temporary
)
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
));
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
);
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
;
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
));
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);
2508 ERR("Unable to move file (error %li)\n",GetLastError());
2519 inline static UINT
get_file_target(MSIPACKAGE
*package
, LPCWSTR file_key
,
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
;
2537 return ERROR_FILE_NOT_FOUND
;
2541 return ERROR_FUNCTION_FAILED
;
2544 static UINT
ACTION_DuplicateFiles(MSIPACKAGE
*package
)
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};
2554 return ERROR_INVALID_HANDLE
;
2556 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2557 if (rc
!= ERROR_SUCCESS
)
2560 rc
= MSI_ViewExecute(view
, 0);
2561 if (rc
!= ERROR_SUCCESS
)
2563 MSI_ViewClose(view
);
2564 msiobj_release(&view
->hdr
);
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
;
2579 rc
= MSI_ViewFetch(view
,&row
);
2580 if (rc
!= ERROR_SUCCESS
)
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
);
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
);
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
);
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
);
2622 if (MSI_RecordIsNull(row
,4))
2624 strcpyW(dest_name
,strrchrW(file_source
,'\\')+1);
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;
2640 WCHAR destkey
[0x100];
2642 MSI_RecordGetStringW(row
,5,destkey
,&sz
);
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
);
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
);
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
);
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
,
2683 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2692 deformat_string(package
, &value
[2], &deformated
);
2694 /* binary value type */
2697 *size
= strlenW(ptr
)/2;
2698 data
= HeapAlloc(GetProcessHeap(),0,*size
);
2710 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2713 HeapFree(GetProcessHeap(),0,deformated
);
2715 TRACE("Data %li bytes(%i)\n",*size
,count
);
2720 deformat_string(package
, &value
[1], &deformated
);
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
);
2741 *type
=REG_EXPAND_SZ
;
2749 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2754 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
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 };
2764 return ERROR_INVALID_HANDLE
;
2766 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2767 if (rc
!= ERROR_SUCCESS
)
2770 rc
= MSI_ViewExecute(view
, 0);
2771 if (rc
!= ERROR_SUCCESS
)
2773 MSI_ViewClose(view
);
2774 msiobj_release(&view
->hdr
);
2778 /* increment progress bar each time action data is sent */
2779 ui_progress(package
,1,1,1,0);
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',
2790 static const WCHAR szHU
[] =
2791 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2796 LPSTR value_data
= NULL
;
2797 HKEY root_key
, hkey
;
2799 WCHAR component
[0x100];
2800 INT component_index
;
2807 rc
= MSI_ViewFetch(view
,&row
);
2808 if (rc
!= ERROR_SUCCESS
)
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
);
2826 /* null values have special meanings during uninstalls and such */
2828 if(MSI_RecordIsNull(row
,5))
2830 msiobj_release(&row
->hdr
);
2834 root
= MSI_RecordGetInteger(row
,2);
2836 MSI_RecordGetStringW(row
,3,key
,&sz
);
2839 if (MSI_RecordIsNull(row
,4))
2842 MSI_RecordGetStringW(row
,4,name
,&sz
);
2844 /* get the root key */
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;
2856 ERR("Unknown root %i\n",root
);
2862 msiobj_release(&row
->hdr
);
2867 if (RegCreateKeyW( root_key
, key
, &hkey
))
2869 ERR("Could not create key %s\n",debugstr_w(key
));
2870 msiobj_release(&row
->hdr
);
2874 value
= load_dynamic_stringW(row
,5);
2875 value_data
= parse_value(package
, value
, &type
, &size
);
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
);
2887 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
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
);
2902 MSI_ViewClose(view
);
2903 msiobj_release(&view
->hdr
);
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
)
2922 /* scan for special characters */
2923 if (!strchrW(ptr
,'[') || (strchrW(ptr
,'[') && !strchrW(ptr
,']')))
2926 size
= (strlenW(ptr
)+1) * sizeof(WCHAR
);
2927 *data
= HeapAlloc(GetProcessHeap(),0,size
);
2932 /* formatted string located */
2933 mark
= strchrW(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
);
2946 size
= sizeof(WCHAR
);
2947 *data
= HeapAlloc(GetProcessHeap(),0,size
);
2952 *strchrW(key
,']')=0;
2953 mark
= strchrW(mark
,']');
2955 TRACE("Current %s .. %s\n",debugstr_w(*data
),debugstr_w(mark
));
2957 rc
= MSI_GetPropertyW(package
, key
, NULL
, &sz
);
2958 if ((rc
== ERROR_SUCCESS
) || (rc
== ERROR_MORE_DATA
))
2963 value
= HeapAlloc(GetProcessHeap(),0,sz
* sizeof(WCHAR
));
2964 MSI_GetPropertyW(package
, key
, value
, &sz
);
2966 chunk
= (strlenW(value
)+1) * sizeof(WCHAR
);
2968 newdata
= HeapReAlloc(GetProcessHeap(),0,*data
,size
);
2970 strcatW(*data
,value
);
2972 TRACE("Current %s .. %s\n",debugstr_w(*data
),debugstr_w(mark
));
2976 chunk
= (strlenW(mark
)+1) * sizeof(WCHAR
);
2978 newdata
= HeapReAlloc(GetProcessHeap(),0,*data
,size
);
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
);
2994 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
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");
3014 if (MSI_GetPropertyW(package
,szlevel
,level
,&sz
)==ERROR_SUCCESS
)
3015 install_level
= atoiW(level
);
3020 rc
= MSI_GetPropertyW(package
,szAddLocal
,NULL
,&sz
);
3021 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_MORE_DATA
)
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
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
)
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};
3070 MSIRECORD
* row
= 0;
3072 TRACE(" InstallValidate \n");
3074 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
3075 if (rc
!= ERROR_SUCCESS
)
3077 rc
= MSI_ViewExecute(view
, 0);
3078 if (rc
!= ERROR_SUCCESS
)
3080 MSI_ViewClose(view
);
3081 msiobj_release(&view
->hdr
);
3086 rc
= MSI_ViewFetch(view
,&row
);
3087 if (rc
!= ERROR_SUCCESS
)
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
)
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
)
3121 rc
= MSI_ViewExecute(view
, 0);
3122 if (rc
!= ERROR_SUCCESS
)
3124 MSI_ViewClose(view
);
3125 msiobj_release(&view
->hdr
);
3130 while (rc
== ERROR_SUCCESS
)
3133 LPWSTR message
= NULL
;
3135 rc
= MSI_ViewFetch(view
,&row
);
3136 if (rc
!= ERROR_SUCCESS
)
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
);
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
);
3169 if ((cmp
->Attributes
& 0x4) || (cmp
->Attributes
& 0x20))
3171 FIXME("UNIMPLEMENTED keypath as Registry or ODBC Source\n");
3177 j
= get_loaded_file(package
,cmp
->KeyPath
);
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];
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 };
3214 return ERROR_INVALID_HANDLE
;
3216 /* writes the Component and Features values to the registry */
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
)
3227 rc
= RegCreateKeyW(hkey
,szFeatures
,&hkey2
);
3228 if (rc
!= ERROR_SUCCESS
)
3231 rc
= RegCreateKeyW(hkey2
,squished_pc
,&hkey3
);
3232 if (rc
!= ERROR_SUCCESS
)
3235 /* here the guids are base 85 encoded */
3236 for (i
= 0; i
< package
->loaded_features
; i
++)
3243 size
= package
->features
[i
].ComponentCount
*21*sizeof(WCHAR
);
3244 data
= HeapAlloc(GetProcessHeap(), 0, size
);
3247 for (j
= 0; j
< package
->features
[i
].ComponentCount
; j
++)
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
,
3255 encode_base85_guid(&clsid
,buf
);
3256 TRACE("to %s\n",debugstr_w(buf
));
3260 size
= strlenW(data
)*sizeof(WCHAR
);
3261 RegSetValueExW(hkey3
,package
->features
[i
].Feature
,0,REG_SZ
,
3263 HeapFree(GetProcessHeap(),0,data
);
3269 rc
= RegCreateKeyW(hkey
,szComponents
,&hkey2
);
3270 if (rc
!= ERROR_SUCCESS
)
3273 for (i
= 0; i
< package
->loaded_components
; i
++)
3275 if (package
->components
[i
].ComponentId
[0]!=0)
3277 WCHAR keypath
[0x1000];
3280 squash_guid(package
->components
[i
].ComponentId
,squished_cc
);
3281 rc
= RegCreateKeyW(hkey2
,squished_cc
,&hkey3
);
3282 if (rc
!= ERROR_SUCCESS
)
3285 resolve_keypath(package
,i
,keypath
);
3287 RegSetValueExW(hkey3
,squished_pc
,0,REG_SZ
,(LPVOID
)keypath
,
3288 (strlenW(keypath
)+1)*sizeof(WCHAR
));
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
);
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
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};
3324 return ERROR_INVALID_HANDLE
;
3326 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3327 if (rc
!= ERROR_SUCCESS
)
3330 rc
= MSI_ViewExecute(view
, 0);
3331 if (rc
!= ERROR_SUCCESS
)
3333 MSI_ViewClose(view
);
3334 msiobj_release(&view
->hdr
);
3340 WCHAR component
[0x100];
3344 rc
= MSI_ViewFetch(view
,&row
);
3345 if (rc
!= ERROR_SUCCESS
)
3352 MSI_RecordGetStringW(row
,3,component
,&sz
);
3354 index
= get_loaded_component(package
,component
);
3357 msiobj_release(&row
->hdr
);
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
);
3369 index
= get_loaded_file(package
,package
->components
[index
].KeyPath
);
3373 msiobj_release(&row
->hdr
);
3377 res
= LoadTypeLib(package
->files
[index
].TargetPath
,&ptLib
);
3380 WCHAR help
[MAX_PATH
];
3381 WCHAR helpid
[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
));
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
));
3404 ITypeLib_Release(ptLib
);
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
);
3418 static UINT
register_appid(MSIPACKAGE
*package
, LPCWSTR clsid
, LPCWSTR app
)
3420 static const WCHAR szAppID
[] = { 'A','p','p','I','D',0 };
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];
3432 return ERROR_INVALID_HANDLE
;
3434 sprintfW(Query
,ExecSeqQuery
,clsid
);
3436 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3437 if (rc
!= ERROR_SUCCESS
)
3440 rc
= MSI_ViewExecute(view
, 0);
3441 if (rc
!= ERROR_SUCCESS
)
3443 MSI_ViewClose(view
);
3444 msiobj_release(&view
->hdr
);
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
);
3461 if (!MSI_RecordIsNull(row
,2))
3463 LPWSTR deformated
=0;
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
,
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};
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};
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};
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
);
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.
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
;
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
)
3571 rc
= MSI_ViewExecute(view
, 0);
3572 if (rc
!= ERROR_SUCCESS
)
3574 MSI_ViewClose(view
);
3575 msiobj_release(&view
->hdr
);
3582 WCHAR buffer
[0x100];
3587 rc
= MSI_ViewFetch(view
,&row
);
3588 if (rc
!= ERROR_SUCCESS
)
3595 MSI_RecordGetStringW(row
,3,buffer
,&sz
);
3597 index
= get_loaded_component(package
,buffer
);
3601 msiobj_release(&row
->hdr
);
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
);
3614 MSI_RecordGetStringW(row
,1,clsid
,&sz
);
3615 RegCreateKeyW(hkey
,clsid
,&hkey2
);
3617 if (!MSI_RecordIsNull(row
,5))
3620 MSI_RecordGetStringW(row
,5,desc
,&sz
);
3622 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)desc
,
3623 (strlenW(desc
)+1)*sizeof(WCHAR
));
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)
3641 if (!MSI_RecordIsNull(row
,4))
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
));
3654 if (!MSI_RecordIsNull(row
,6))
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
);
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
);
3681 static UINT
register_progid_base(MSIRECORD
* row
, LPWSTR clsid
)
3683 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
3685 WCHAR buffer
[0x100];
3690 MSI_RecordGetStringW(row
,1,buffer
,&sz
);
3691 RegCreateKeyW(HKEY_CLASSES_ROOT
,buffer
,&hkey
);
3693 if (!MSI_RecordIsNull(row
,4))
3696 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
3697 RegSetValueExW(hkey
,NULL
,0,REG_SZ
,(LPVOID
)buffer
, (strlenW(buffer
)+1) *
3701 if (!MSI_RecordIsNull(row
,3))
3705 MSI_RecordGetStringW(row
,3,buffer
,&sz
);
3706 RegCreateKeyW(hkey
,szCLSID
,&hkey2
);
3707 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)buffer
, (strlenW(buffer
)+1) *
3711 strcpyW(clsid
,buffer
);
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
,
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',' ','=',' ','`'
3737 WCHAR Query
[0x1000];
3740 return ERROR_INVALID_HANDLE
;
3742 sprintfW(Query
,Query_t
,parent
);
3744 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3745 if (rc
!= ERROR_SUCCESS
)
3748 rc
= MSI_ViewExecute(view
, 0);
3749 if (rc
!= ERROR_SUCCESS
)
3751 MSI_ViewClose(view
);
3752 msiobj_release(&view
->hdr
);
3756 rc
= MSI_ViewFetch(view
,&row
);
3757 if (rc
!= ERROR_SUCCESS
)
3759 MSI_ViewClose(view
);
3760 msiobj_release(&view
->hdr
);
3764 register_progid(package
,row
,clsid
);
3766 msiobj_release(&row
->hdr
);
3767 MSI_ViewClose(view
);
3768 msiobj_release(&view
->hdr
);
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
);
3780 WCHAR buffer
[0x1000];
3783 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
3786 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
3787 rc
= register_parent_progid(package
,buffer
,clsid
);
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) *
3798 if (!MSI_RecordIsNull(row
,4))
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");
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
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};
3832 return ERROR_INVALID_HANDLE
;
3834 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3835 if (rc
!= ERROR_SUCCESS
)
3838 rc
= MSI_ViewExecute(view
, 0);
3839 if (rc
!= ERROR_SUCCESS
)
3841 MSI_ViewClose(view
);
3842 msiobj_release(&view
->hdr
);
3848 WCHAR clsid
[0x1000];
3850 rc
= MSI_ViewFetch(view
,&row
);
3851 if (rc
!= ERROR_SUCCESS
)
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
);
3867 static UINT
build_icon_path(MSIPACKAGE
*package
, LPCWSTR icon_name
,
3870 WCHAR ProductCode
[0x100];
3871 WCHAR SystemFolder
[MAX_PATH
];
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};
3882 MSI_GetPropertyW(package
,szProductCode
,ProductCode
,&sz
);
3883 if (strlenW(ProductCode
)==0)
3884 return ERROR_FUNCTION_FAILED
;
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
)
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};
3911 return ERROR_INVALID_HANDLE
;
3913 res
= CoInitialize( NULL
);
3916 ERR("CoInitialize failed\n");
3917 return ERROR_FUNCTION_FAILED
;
3920 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3921 if (rc
!= ERROR_SUCCESS
)
3924 rc
= MSI_ViewExecute(view
, 0);
3925 if (rc
!= ERROR_SUCCESS
)
3927 MSI_ViewClose(view
);
3928 msiobj_release(&view
->hdr
);
3934 WCHAR target_file
[MAX_PATH
];
3935 WCHAR buffer
[0x100];
3938 static const WCHAR szlnk
[]={'.','l','n','k',0};
3940 rc
= MSI_ViewFetch(view
,&row
);
3941 if (rc
!= ERROR_SUCCESS
)
3948 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
3950 index
= get_loaded_component(package
,buffer
);
3954 msiobj_release(&row
->hdr
);
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
);
3966 ui_actiondata(package
,szCreateShortcuts
,row
);
3968 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
3969 &IID_IShellLinkW
, (LPVOID
*) &sl
);
3973 ERR("Is IID_IShellLink\n");
3974 msiobj_release(&row
->hdr
);
3978 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
3981 ERR("Is IID_IPersistFile\n");
3982 msiobj_release(&row
->hdr
);
3987 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
3988 resolve_folder(package
, buffer
,target_file
,FALSE
,FALSE
,NULL
);
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
);
3998 MSI_RecordGetStringW(row
,5,buffer
,&sz
);
3999 if (strchrW(buffer
,'['))
4002 deformat_string(package
,buffer
,&deformated
);
4003 IShellLinkW_SetPath(sl
,deformated
);
4004 HeapFree(GetProcessHeap(),0,deformated
);
4008 FIXME("UNHANDLED shortcut format, advertised shortcut\n");
4009 IPersistFile_Release( pf
);
4010 IShellLinkW_Release( sl
);
4011 msiobj_release(&row
->hdr
);
4015 if (!MSI_RecordIsNull(row
,6))
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))
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
];
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
];
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
);
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
)
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};
4098 return ERROR_INVALID_HANDLE
;
4100 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
4101 if (rc
!= ERROR_SUCCESS
)
4104 rc
= MSI_ViewExecute(view
, 0);
4105 if (rc
!= ERROR_SUCCESS
)
4107 MSI_ViewClose(view
);
4108 msiobj_release(&view
->hdr
);
4115 WCHAR FilePath
[MAX_PATH
];
4116 WCHAR FileName
[MAX_PATH
];
4119 rc
= MSI_ViewFetch(view
,&row
);
4120 if (rc
!= ERROR_SUCCESS
)
4127 MSI_RecordGetStringW(row
,1,FileName
,&sz
);
4130 ERR("Unable to get FileName\n");
4131 msiobj_release(&row
->hdr
);
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
);
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
);
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
);
4173 /* Msi functions that seem appropriate here */
4174 UINT WINAPI
MsiDoActionA( MSIHANDLE hInstall
, LPCSTR szAction
)
4179 TRACE(" exteral attempt at action %s\n",szAction
);
4182 return ERROR_FUNCTION_FAILED
;
4184 return ERROR_FUNCTION_FAILED
;
4186 szwAction
= strdupAtoW(szAction
);
4189 return ERROR_FUNCTION_FAILED
;
4192 rc
= MsiDoActionW(hInstall
, szwAction
);
4193 HeapFree(GetProcessHeap(),0,szwAction
);
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
);
4207 ret
= ACTION_PerformAction(package
,szAction
);
4208 msiobj_release( &package
->hdr
);
4213 UINT WINAPI
MsiGetTargetPathA( MSIHANDLE hInstall
, LPCSTR szFolder
,
4214 LPSTR szPathBuf
, DWORD
* pcchPathBuf
)
4220 TRACE("getting folder %s %p %li\n",szFolder
,szPathBuf
, *pcchPathBuf
);
4223 return ERROR_FUNCTION_FAILED
;
4225 return ERROR_FUNCTION_FAILED
;
4227 szwFolder
= strdupAtoW(szFolder
);
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
);
4245 UINT WINAPI
MsiGetTargetPathW( MSIHANDLE hInstall
, LPCWSTR szFolder
, LPWSTR
4246 szPathBuf
, DWORD
* pcchPathBuf
)
4248 WCHAR path
[MAX_PATH
];
4250 MSIPACKAGE
*package
;
4252 TRACE("(%s %p %li)\n",debugstr_w(szFolder
),szPathBuf
,*pcchPathBuf
);
4254 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_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
));
4276 UINT WINAPI
MsiGetSourcePathA( MSIHANDLE hInstall
, LPCSTR szFolder
,
4277 LPSTR szPathBuf
, DWORD
* pcchPathBuf
)
4283 TRACE("getting source %s %p %li\n",szFolder
,szPathBuf
, *pcchPathBuf
);
4286 return ERROR_FUNCTION_FAILED
;
4288 return ERROR_FUNCTION_FAILED
;
4290 szwFolder
= strdupAtoW(szFolder
);
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
);
4307 UINT WINAPI
MsiGetSourcePathW( MSIHANDLE hInstall
, LPCWSTR szFolder
, LPWSTR
4308 szPathBuf
, DWORD
* pcchPathBuf
)
4310 WCHAR path
[MAX_PATH
];
4312 MSIPACKAGE
*package
;
4314 TRACE("(%s %p %li)\n",debugstr_w(szFolder
),szPathBuf
,*pcchPathBuf
);
4316 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_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
));
4338 UINT WINAPI
MsiSetTargetPathA(MSIHANDLE hInstall
, LPCSTR szFolder
,
4339 LPCSTR szFolderPath
)
4342 LPWSTR szwFolderPath
;
4346 return ERROR_FUNCTION_FAILED
;
4348 return ERROR_FUNCTION_FAILED
;
4350 szwFolder
= strdupAtoW(szFolder
);
4352 return ERROR_FUNCTION_FAILED
;
4354 szwFolderPath
= strdupAtoW(szFolderPath
);
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
);
4369 UINT
MSI_SetTargetPathW(MSIPACKAGE
*package
, LPCWSTR szFolder
,
4370 LPCWSTR szFolderPath
)
4373 WCHAR path
[MAX_PATH
];
4376 TRACE("(%p %s %s)\n",package
, debugstr_w(szFolder
),debugstr_w(szFolderPath
));
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
);
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
,
4401 return ERROR_SUCCESS
;
4404 UINT WINAPI
MsiSetTargetPathW(MSIHANDLE hInstall
, LPCWSTR szFolder
,
4405 LPCWSTR szFolderPath
)
4407 MSIPACKAGE
*package
;
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
);
4418 BOOL WINAPI
MsiGetMode(MSIHANDLE hInstall
, DWORD iRunMode
)
4420 FIXME("STUB (%li)\n",iRunMode
);
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
;
4434 szwFeature
= strdupAtoW(szFeature
);
4437 return ERROR_FUNCTION_FAILED
;
4439 rc
= MsiSetFeatureStateW(hInstall
,szwFeature
, iState
);
4441 HeapFree(GetProcessHeap(),0,szwFeature
);
4446 UINT WINAPI
MsiSetFeatureStateW(MSIHANDLE hInstall
, LPCWSTR szFeature
,
4447 INSTALLSTATE iState
)
4449 MSIPACKAGE
* package
;
4452 TRACE(" %s to %i\n",debugstr_w(szFeature
), iState
);
4454 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
4456 return ERROR_INVALID_HANDLE
;
4458 index
= get_loaded_feature(package
,szFeature
);
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
;
4473 szwFeature
= strdupAtoW(szFeature
);
4475 rc
= MsiGetFeatureStateW(hInstall
,szwFeature
,piInstalled
, piAction
);
4477 HeapFree( GetProcessHeap(), 0 , szwFeature
);
4482 UINT
MSI_GetFeatureStateW(MSIPACKAGE
*package
, LPWSTR szFeature
,
4483 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
4487 index
= get_loaded_feature(package
,szFeature
);
4489 return ERROR_UNKNOWN_FEATURE
;
4492 *piInstalled
= package
->features
[index
].State
;
4496 if (package
->features
[index
].Enabled
)
4497 *piAction
= INSTALLSTATE_LOCAL
;
4499 *piAction
= INSTALLSTATE_UNKNOWN
;
4502 return ERROR_SUCCESS
;
4505 UINT WINAPI
MsiGetFeatureStateW(MSIHANDLE hInstall
, LPWSTR szFeature
,
4506 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
4508 MSIPACKAGE
* package
;
4511 TRACE("%ld %s %p %p\n", hInstall
, debugstr_w(szFeature
), piInstalled
,
4514 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
4516 return ERROR_INVALID_HANDLE
;
4517 ret
= MSI_GetFeatureStateW(package
, szFeature
, piInstalled
, piAction
);
4518 msiobj_release( &package
->hdr
);
4522 UINT WINAPI
MsiGetComponentStateA(MSIHANDLE hInstall
, LPSTR szComponent
,
4523 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
4525 LPWSTR szwComponent
= NULL
;
4528 szwComponent
= strdupAtoW(szComponent
);
4530 rc
= MsiGetComponentStateW(hInstall
,szwComponent
,piInstalled
, piAction
);
4532 HeapFree( GetProcessHeap(), 0 , szwComponent
);
4537 UINT
MSI_GetComponentStateW(MSIPACKAGE
*package
, LPWSTR szComponent
,
4538 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
4542 TRACE("%p %s %p %p\n", package
, debugstr_w(szComponent
), piInstalled
,
4545 index
= get_loaded_component(package
,szComponent
);
4547 return ERROR_UNKNOWN_COMPONENT
;
4550 *piInstalled
= package
->components
[index
].State
;
4554 if (package
->components
[index
].Enabled
&&
4555 package
->components
[index
].FeatureState
)
4556 *piAction
= INSTALLSTATE_LOCAL
;
4558 *piAction
= INSTALLSTATE_UNKNOWN
;
4561 return ERROR_SUCCESS
;
4564 UINT WINAPI
MsiGetComponentStateW(MSIHANDLE hInstall
, LPWSTR szComponent
,
4565 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
4567 MSIPACKAGE
* package
;
4570 TRACE("%ld %s %p %p\n", hInstall
, debugstr_w(szComponent
),
4571 piInstalled
, piAction
);
4573 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
4575 return ERROR_INVALID_HANDLE
;
4576 ret
= MSI_GetComponentStateW( package
, szComponent
, piInstalled
, piAction
);
4577 msiobj_release( &package
->hdr
);
4582 static UINT
ACTION_Template(MSIPACKAGE
*package
)
4586 MSIRECORD
* row
= 0;
4587 static const WCHAR ExecSeqQuery
[] = {0};
4589 rc
= MsiDatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4590 if (rc
!= ERROR_SUCCESS
)
4593 rc
= MsiViewExecute(view
, 0);
4594 if (rc
!= ERROR_SUCCESS
)
4597 msiobj_release(&view
->hdr
);
4603 rc
= MsiViewFetch(view
,&row
);
4604 if (rc
!= ERROR_SUCCESS
)
4610 msiobj_release(&row
->hdr
);
4613 msiobj_release(&view
->hdr
);