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
38 #include "wine/debug.h"
42 #include "msvcrt/fcntl.h"
49 #include "wine/unicode.h"
53 #define REG_PROGRESS_VALUE 13200
54 #define COMPONENT_PROGRESS_VALUE 24000
56 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
61 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
);
62 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
);
64 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
);
65 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
);
67 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
);
68 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
);
69 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
);
70 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
);
71 static UINT
ACTION_FileCost(MSIPACKAGE
*package
);
72 static UINT
ACTION_InstallFiles(MSIPACKAGE
*package
);
73 static UINT
ACTION_DuplicateFiles(MSIPACKAGE
*package
);
74 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
);
75 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
);
76 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
);
77 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
);
78 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
);
79 static UINT
ACTION_RegisterClassInfo(MSIPACKAGE
*package
);
80 static UINT
ACTION_RegisterProgIdInfo(MSIPACKAGE
*package
);
81 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
);
82 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
);
83 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
);
84 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
);
85 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
);
86 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
);
87 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
);
88 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
);
89 static UINT
ACTION_ForceReboot(MSIPACKAGE
*package
);
92 static UINT
build_icon_path(MSIPACKAGE
*package
, LPCWSTR icon_name
,
96 * consts and values used
98 static const WCHAR cszSourceDir
[] = {'S','o','u','r','c','e','D','i','r',0};
99 static const WCHAR cszRootDrive
[] = {'R','O','O','T','D','R','I','V','E',0};
100 static const WCHAR cszTargetDir
[] = {'T','A','R','G','E','T','D','I','R',0};
101 static const WCHAR cszTempFolder
[]= {'T','e','m','p','F','o','l','d','e','r',0};
102 static const WCHAR cszDatabase
[]={'D','A','T','A','B','A','S','E',0};
103 static const WCHAR c_collen
[] = {'C',':','\\',0};
105 static const WCHAR cszbs
[]={'\\',0};
107 const static WCHAR szCreateFolders
[] =
108 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
109 const static WCHAR szCostFinalize
[] =
110 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
111 const static WCHAR szInstallFiles
[] =
112 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
113 const static WCHAR szDuplicateFiles
[] =
114 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
115 const static WCHAR szWriteRegistryValues
[] =
116 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
117 const static WCHAR szCostInitialize
[] =
118 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
119 const static WCHAR szFileCost
[] = {'F','i','l','e','C','o','s','t',0};
120 const static WCHAR szInstallInitialize
[] =
121 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
122 const static WCHAR szInstallValidate
[] =
123 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
124 const static WCHAR szLaunchConditions
[] =
125 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
126 const static WCHAR szProcessComponents
[] =
127 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
128 const static WCHAR szRegisterTypeLibraries
[] =
129 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r',
131 const static WCHAR szRegisterClassInfo
[] =
132 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
133 const static WCHAR szRegisterProgIdInfo
[] =
134 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
135 const static WCHAR szCreateShortcuts
[] =
136 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
137 const static WCHAR szPublishProduct
[] =
138 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
139 const static WCHAR szWriteIniValues
[] =
140 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
141 const static WCHAR szSelfRegModules
[] =
142 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
143 const static WCHAR szPublishFeatures
[] =
144 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
145 const static WCHAR szRegisterProduct
[] =
146 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
147 const static WCHAR szInstallExecute
[] =
148 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
149 const static WCHAR szInstallExecuteAgain
[] =
150 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
151 const static WCHAR szInstallFinalize
[] =
152 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
153 const static WCHAR szForceReboot
[] =
154 {'F','o','r','c','e','R','e','b','o','o','t',0};
156 /********************************************************
157 * helper functions to get around current HACKS and such
158 ********************************************************/
159 inline static void reduce_to_longfilename(WCHAR
* filename
)
161 LPWSTR p
= strchrW(filename
,'|');
163 memmove(filename
, p
+1, (strlenW(p
+1)+1)*sizeof(WCHAR
));
166 WCHAR
*load_dynamic_stringW(MSIRECORD
*row
, INT index
)
173 if (MSI_RecordIsNull(row
,index
))
176 rc
= MSI_RecordGetStringW(row
,index
,NULL
,&sz
);
178 /* having an empty string is different than NULL */
181 ret
= HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR
));
187 ret
= HeapAlloc(GetProcessHeap(),0,sz
* sizeof (WCHAR
));
188 rc
= MSI_RecordGetStringW(row
,index
,ret
,&sz
);
189 if (rc
!=ERROR_SUCCESS
)
191 ERR("Unable to load dynamic string\n");
192 HeapFree(GetProcessHeap(), 0, ret
);
198 LPWSTR
load_dynamic_property(MSIPACKAGE
*package
, LPCWSTR prop
, UINT
* rc
)
204 r
= MSI_GetPropertyW(package
, prop
, NULL
, &sz
);
205 if (r
!= ERROR_SUCCESS
&& r
!= ERROR_MORE_DATA
)
212 str
= HeapAlloc(GetProcessHeap(),0,sz
*sizeof(WCHAR
));
213 r
= MSI_GetPropertyW(package
, prop
, str
, &sz
);
214 if (r
!= ERROR_SUCCESS
)
216 HeapFree(GetProcessHeap(),0,str
);
224 int get_loaded_component(MSIPACKAGE
* package
, LPCWSTR Component
)
229 for (i
= 0; i
< package
->loaded_components
; i
++)
231 if (strcmpW(Component
,package
->components
[i
].Component
)==0)
240 int get_loaded_feature(MSIPACKAGE
* package
, LPCWSTR Feature
)
245 for (i
= 0; i
< package
->loaded_features
; i
++)
247 if (strcmpW(Feature
,package
->features
[i
].Feature
)==0)
256 int get_loaded_file(MSIPACKAGE
* package
, LPCWSTR file
)
261 for (i
= 0; i
< package
->loaded_files
; i
++)
263 if (strcmpW(file
,package
->files
[i
].File
)==0)
272 int track_tempfile(MSIPACKAGE
*package
, LPCWSTR name
, LPCWSTR path
)
280 for (i
=0; i
< package
->loaded_files
; i
++)
281 if (strcmpW(package
->files
[i
].File
,name
)==0)
284 index
= package
->loaded_files
;
285 package
->loaded_files
++;
286 if (package
->loaded_files
== 1)
287 package
->files
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE
));
289 package
->files
= HeapReAlloc(GetProcessHeap(),0,
290 package
->files
, package
->loaded_files
* sizeof(MSIFILE
));
292 memset(&package
->files
[index
],0,sizeof(MSIFILE
));
294 package
->files
[index
].File
= dupstrW(name
);
295 package
->files
[index
].TargetPath
= dupstrW(path
);
296 package
->files
[index
].Temporary
= TRUE
;
298 TRACE("Tracking tempfile (%s)\n",debugstr_w(package
->files
[index
].File
));
303 static void remove_tracked_tempfiles(MSIPACKAGE
* package
)
310 for (i
= 0; i
< package
->loaded_files
; i
++)
312 if (package
->files
[i
].Temporary
)
314 TRACE("Cleaning up %s\n",debugstr_w(package
->files
[i
].TargetPath
));
315 DeleteFileW(package
->files
[i
].TargetPath
);
321 /* wrapper to resist a need for a full rewrite right now */
322 DWORD
deformat_string(MSIPACKAGE
*package
, LPCWSTR ptr
, WCHAR
** data
)
326 MSIRECORD
*rec
= MSI_CreateRecord(1);
328 WCHAR size_buf
[2] = {' ',0};
330 MSI_RecordSetStringW(rec
,0,ptr
);
331 MSI_FormatRecordW(package
,rec
,size_buf
,&size
);
335 *data
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
336 MSI_FormatRecordW(package
,rec
,*data
,&size
);
337 return sizeof(WCHAR
)*size
;
345 /* Called when the package is being closed */
346 void ACTION_free_package_structures( MSIPACKAGE
* package
)
350 TRACE("Freeing package action data\n");
352 remove_tracked_tempfiles(package
);
354 /* No dynamic buffers in features */
355 if (package
->features
&& package
->loaded_features
> 0)
356 HeapFree(GetProcessHeap(),0,package
->features
);
358 for (i
= 0; i
< package
->loaded_folders
; i
++)
360 HeapFree(GetProcessHeap(),0,package
->folders
[i
].Directory
);
361 HeapFree(GetProcessHeap(),0,package
->folders
[i
].TargetDefault
);
362 HeapFree(GetProcessHeap(),0,package
->folders
[i
].SourceDefault
);
363 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedTarget
);
364 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedSource
);
365 HeapFree(GetProcessHeap(),0,package
->folders
[i
].Property
);
367 if (package
->folders
&& package
->loaded_folders
> 0)
368 HeapFree(GetProcessHeap(),0,package
->folders
);
370 /* no dynamic buffers in components */
371 if (package
->components
&& package
->loaded_components
> 0)
372 HeapFree(GetProcessHeap(),0,package
->components
);
374 for (i
= 0; i
< package
->loaded_files
; i
++)
376 HeapFree(GetProcessHeap(),0,package
->files
[i
].File
);
377 HeapFree(GetProcessHeap(),0,package
->files
[i
].FileName
);
378 HeapFree(GetProcessHeap(),0,package
->files
[i
].Version
);
379 HeapFree(GetProcessHeap(),0,package
->files
[i
].Language
);
380 HeapFree(GetProcessHeap(),0,package
->files
[i
].SourcePath
);
381 HeapFree(GetProcessHeap(),0,package
->files
[i
].TargetPath
);
384 if (package
->files
&& package
->loaded_files
> 0)
385 HeapFree(GetProcessHeap(),0,package
->files
);
387 for (i
= 0; i
< package
->DeferredActionCount
; i
++)
388 HeapFree(GetProcessHeap(),0,package
->DeferredAction
[i
]);
389 HeapFree(GetProcessHeap(),0,package
->DeferredAction
);
391 for (i
= 0; i
< package
->CommitActionCount
; i
++)
392 HeapFree(GetProcessHeap(),0,package
->CommitAction
[i
]);
393 HeapFree(GetProcessHeap(),0,package
->CommitAction
);
395 HeapFree(GetProcessHeap(),0,package
->PackagePath
);
398 static void ui_progress(MSIPACKAGE
*package
, int a
, int b
, int c
, int d
)
402 row
= MSI_CreateRecord(4);
403 MSI_RecordSetInteger(row
,1,a
);
404 MSI_RecordSetInteger(row
,2,b
);
405 MSI_RecordSetInteger(row
,3,c
);
406 MSI_RecordSetInteger(row
,4,d
);
407 MSI_ProcessMessage(package
, INSTALLMESSAGE_PROGRESS
, row
);
408 msiobj_release(&row
->hdr
);
411 static void ui_actiondata(MSIPACKAGE
*package
, LPCWSTR action
, MSIRECORD
* record
)
413 static const WCHAR Query_t
[] =
414 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
415 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
416 ' ','\'','%','s','\'',0};
423 if (!package
->LastAction
|| strcmpW(package
->LastAction
,action
))
425 rc
= MSI_OpenQuery(package
->db
, &view
, Query_t
, action
);
426 if (rc
!= ERROR_SUCCESS
)
429 rc
= MSI_ViewExecute(view
, 0);
430 if (rc
!= ERROR_SUCCESS
)
435 rc
= MSI_ViewFetch(view
,&row
);
436 if (rc
!= ERROR_SUCCESS
)
442 if (MSI_RecordIsNull(row
,3))
444 msiobj_release(&row
->hdr
);
446 msiobj_release(&view
->hdr
);
450 /* update the cached actionformat */
451 HeapFree(GetProcessHeap(),0,package
->ActionFormat
);
452 package
->ActionFormat
= load_dynamic_stringW(row
,3);
454 HeapFree(GetProcessHeap(),0,package
->LastAction
);
455 package
->LastAction
= dupstrW(action
);
457 msiobj_release(&row
->hdr
);
459 msiobj_release(&view
->hdr
);
462 MSI_RecordSetStringW(record
,0,package
->ActionFormat
);
464 MSI_FormatRecordW(package
,record
,message
,&size
);
466 row
= MSI_CreateRecord(1);
467 MSI_RecordSetStringW(row
,1,message
);
469 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONDATA
, row
);
470 msiobj_release(&row
->hdr
);
474 static void ui_actionstart(MSIPACKAGE
*package
, LPCWSTR action
)
476 static const WCHAR template_s
[]=
477 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ','%','s','.',0};
478 static const WCHAR format
[] =
479 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
480 static const WCHAR Query_t
[] =
481 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
482 'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
483 ' ','\'','%','s','\'',0};
489 WCHAR
*ActionText
=NULL
;
491 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
493 rc
= MSI_OpenQuery(package
->db
, &view
, Query_t
, action
);
494 if (rc
!= ERROR_SUCCESS
)
496 rc
= MSI_ViewExecute(view
, 0);
497 if (rc
!= ERROR_SUCCESS
)
500 msiobj_release(&view
->hdr
);
503 rc
= MSI_ViewFetch(view
,&row
);
504 if (rc
!= ERROR_SUCCESS
)
507 msiobj_release(&view
->hdr
);
511 ActionText
= load_dynamic_stringW(row
,2);
512 msiobj_release(&row
->hdr
);
514 msiobj_release(&view
->hdr
);
516 sprintfW(message
,template_s
,timet
,action
,ActionText
);
518 row
= MSI_CreateRecord(1);
519 MSI_RecordSetStringW(row
,1,message
);
521 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONSTART
, row
);
522 msiobj_release(&row
->hdr
);
523 HeapFree(GetProcessHeap(),0,ActionText
);
526 static void ui_actioninfo(MSIPACKAGE
*package
, LPCWSTR action
, BOOL start
,
530 static const WCHAR template_s
[]=
531 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ','%','s',
533 static const WCHAR template_e
[]=
534 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ','%','s',
535 '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ','%','i','.',0};
536 static const WCHAR format
[] =
537 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
541 GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, NULL
, format
, timet
, 0x100);
543 sprintfW(message
,template_s
,timet
,action
);
545 sprintfW(message
,template_e
,timet
,action
,rc
);
547 row
= MSI_CreateRecord(1);
548 MSI_RecordSetStringW(row
,1,message
);
550 MSI_ProcessMessage(package
, INSTALLMESSAGE_INFO
, row
);
551 msiobj_release(&row
->hdr
);
555 * build_directory_name()
557 * This function is to save messing round with directory names
558 * It handles adding backslashes between path segments,
559 * and can add \ at the end of the directory name if told to.
561 * It takes a variable number of arguments.
562 * It always allocates a new string for the result, so make sure
563 * to free the return value when finished with it.
565 * The first arg is the number of path segments that follow.
566 * The arguments following count are a list of path segments.
567 * A path segment may be NULL.
569 * Path segments will be added with a \ separating them.
570 * A \ will not be added after the last segment, however if the
571 * last segment is NULL, then the last character will be a \
574 static LPWSTR
build_directory_name(DWORD count
, ...)
581 for(i
=0; i
<count
; i
++)
583 LPCWSTR str
= va_arg(va
,LPCWSTR
);
585 sz
+= strlenW(str
) + 1;
589 dir
= HeapAlloc(GetProcessHeap(), 0, sz
*sizeof(WCHAR
));
593 for(i
=0; i
<count
; i
++)
595 LPCWSTR str
= va_arg(va
,LPCWSTR
);
599 if( ((i
+1)!=count
) && dir
[strlenW(dir
)-1]!='\\')
606 /****************************************************
607 * TOP level entry points
608 *****************************************************/
610 UINT
ACTION_DoTopLevelINSTALL(MSIPACKAGE
*package
, LPCWSTR szPackagePath
,
611 LPCWSTR szCommandLine
)
616 static const WCHAR szUILevel
[] = {'U','I','L','e','v','e','l',0};
617 static const WCHAR szAction
[] = {'A','C','T','I','O','N',0};
618 static const WCHAR szInstall
[] = {'I','N','S','T','A','L','L',0};
620 MSI_SetPropertyW(package
, szAction
, szInstall
);
624 LPWSTR p
, check
, path
;
626 package
->PackagePath
= dupstrW(szPackagePath
);
627 path
= dupstrW(szPackagePath
);
628 p
= strrchrW(path
,'\\');
635 check
= load_dynamic_property(package
, cszSourceDir
,NULL
);
637 MSI_SetPropertyW(package
, cszSourceDir
, path
);
639 HeapFree(GetProcessHeap(), 0, check
);
641 HeapFree(GetProcessHeap(), 0, path
);
647 ptr
= (LPWSTR
)szCommandLine
;
654 TRACE("Looking at %s\n",debugstr_w(ptr
));
656 ptr2
= strchrW(ptr
,'=');
662 while (*ptr
== ' ') ptr
++;
664 prop
= HeapAlloc(GetProcessHeap(),0,(len
+1)*sizeof(WCHAR
));
665 strncpyW(prop
,ptr
,len
);
671 while (*ptr
&& (quote
|| (!quote
&& *ptr
!=' ')))
684 val
= HeapAlloc(GetProcessHeap(),0,(len
+1)*sizeof(WCHAR
));
685 strncpyW(val
,ptr2
,len
);
688 if (strlenW(prop
) > 0)
690 TRACE("Found commandline property (%s) = (%s)\n",
691 debugstr_w(prop
), debugstr_w(val
));
692 MSI_SetPropertyW(package
,prop
,val
);
694 HeapFree(GetProcessHeap(),0,val
);
695 HeapFree(GetProcessHeap(),0,prop
);
702 if (MSI_GetPropertyW(package
,szUILevel
,buffer
,&sz
) == ERROR_SUCCESS
)
704 if (atoiW(buffer
) >= INSTALLUILEVEL_REDUCED
)
706 rc
= ACTION_ProcessUISequence(package
);
707 if (rc
== ERROR_SUCCESS
)
708 rc
= ACTION_ProcessExecSequence(package
,TRUE
);
711 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
714 rc
= ACTION_ProcessExecSequence(package
,FALSE
);
716 /* process the ending type action */
717 if (rc
== ERROR_SUCCESS
)
718 rc
= ACTION_PerformActionSequence(package
,-1);
719 else if (rc
== ERROR_FUNCTION_FAILED
)
720 rc
= ACTION_PerformActionSequence(package
,-3);
722 /* finish up running custom actions */
723 ACTION_FinishCustomActions(package
);
728 static UINT
ACTION_PerformActionSequence(MSIPACKAGE
*package
, UINT seq
)
735 static const WCHAR ExecSeqQuery
[] = {
736 's','e','l','e','c','t',' ','*',' ',
738 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
739 'S','e','q','u','e','n','c','e',' ',
740 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
743 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
745 if (rc
== ERROR_SUCCESS
)
747 rc
= MSI_ViewExecute(view
, 0);
749 if (rc
!= ERROR_SUCCESS
)
752 msiobj_release(&view
->hdr
);
756 TRACE("Running the actions\n");
758 rc
= MSI_ViewFetch(view
,&row
);
759 if (rc
!= ERROR_SUCCESS
)
765 /* check conditions */
766 if (!MSI_RecordIsNull(row
,2))
769 cond
= load_dynamic_stringW(row
,2);
773 /* this is a hack to skip errors in the condition code */
774 if (MSI_EvaluateConditionW(package
, cond
) == MSICONDITION_FALSE
)
776 HeapFree(GetProcessHeap(),0,cond
);
777 msiobj_release(&row
->hdr
);
781 HeapFree(GetProcessHeap(),0,cond
);
786 rc
= MSI_RecordGetStringW(row
,1,buffer
,&sz
);
787 if (rc
!= ERROR_SUCCESS
)
789 ERR("Error is %x\n",rc
);
790 msiobj_release(&row
->hdr
);
794 rc
= ACTION_PerformAction(package
,buffer
);
795 msiobj_release(&row
->hdr
);
798 msiobj_release(&view
->hdr
);
806 static UINT
ACTION_ProcessExecSequence(MSIPACKAGE
*package
, BOOL UIran
)
810 static const WCHAR ExecSeqQuery
[] = {
811 's','e','l','e','c','t',' ','*',' ',
813 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
814 'S','e','q','u','e','n','c','e',' ',
815 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
816 '>',' ','%','i',' ','o','r','d','e','r',' ',
817 'b','y',' ','S','e','q','u','e','n','c','e',0 };
819 static const WCHAR IVQuery
[] = {
820 's','e','l','e','c','t',' ','S','e','q','u','e','n','c','e',' ',
821 'f','r','o','m',' ','I','n','s','t','a','l','l',
822 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e',' ',
823 'w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',' ',
824 '`','I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`',
828 /* get the sequence number */
831 rc
= MSI_DatabaseOpenViewW(package
->db
, IVQuery
, &view
);
832 if (rc
!= ERROR_SUCCESS
)
834 rc
= MSI_ViewExecute(view
, 0);
835 if (rc
!= ERROR_SUCCESS
)
838 msiobj_release(&view
->hdr
);
841 rc
= MSI_ViewFetch(view
,&row
);
842 if (rc
!= ERROR_SUCCESS
)
845 msiobj_release(&view
->hdr
);
848 seq
= MSI_RecordGetInteger(row
,1);
849 msiobj_release(&row
->hdr
);
851 msiobj_release(&view
->hdr
);
854 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, seq
);
855 if (rc
== ERROR_SUCCESS
)
857 rc
= MSI_ViewExecute(view
, 0);
859 if (rc
!= ERROR_SUCCESS
)
862 msiobj_release(&view
->hdr
);
866 TRACE("Running the actions\n");
873 rc
= MSI_ViewFetch(view
,&row
);
874 if (rc
!= ERROR_SUCCESS
)
880 /* check conditions */
881 if (!MSI_RecordIsNull(row
,2))
884 cond
= load_dynamic_stringW(row
,2);
888 /* this is a hack to skip errors in the condition code */
889 if (MSI_EvaluateConditionW(package
, cond
) ==
892 HeapFree(GetProcessHeap(),0,cond
);
893 msiobj_release(&row
->hdr
);
897 HeapFree(GetProcessHeap(),0,cond
);
902 rc
= MSI_RecordGetStringW(row
,1,buffer
,&sz
);
903 if (rc
!= ERROR_SUCCESS
)
905 ERR("Error is %x\n",rc
);
906 msiobj_release(&row
->hdr
);
910 rc
= ACTION_PerformAction(package
,buffer
);
912 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
915 if (rc
!= ERROR_SUCCESS
)
917 ERR("Execution halted due to error (%i)\n",rc
);
918 msiobj_release(&row
->hdr
);
922 msiobj_release(&row
->hdr
);
926 msiobj_release(&view
->hdr
);
934 static UINT
ACTION_ProcessUISequence(MSIPACKAGE
*package
)
938 static const WCHAR ExecSeqQuery
[] = {
939 's','e','l','e','c','t',' ','*',' ',
940 'f','r','o','m',' ','I','n','s','t','a','l','l',
941 'U','I','S','e','q','u','e','n','c','e',' ',
942 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', '>',' ','0',' ',
943 'o','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e',0};
945 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
947 if (rc
== ERROR_SUCCESS
)
949 rc
= MSI_ViewExecute(view
, 0);
951 if (rc
!= ERROR_SUCCESS
)
954 msiobj_release(&view
->hdr
);
958 TRACE("Running the actions \n");
966 rc
= MSI_ViewFetch(view
,&row
);
967 if (rc
!= ERROR_SUCCESS
)
973 /* check conditions */
974 if (!MSI_RecordIsNull(row
,2))
977 cond
= load_dynamic_stringW(row
,2);
981 /* this is a hack to skip errors in the condition code */
982 if (MSI_EvaluateConditionW(package
, cond
) ==
985 HeapFree(GetProcessHeap(),0,cond
);
986 msiobj_release(&row
->hdr
);
990 HeapFree(GetProcessHeap(),0,cond
);
995 rc
= MSI_RecordGetStringW(row
,1,buffer
,&sz
);
996 if (rc
!= ERROR_SUCCESS
)
998 ERR("Error is %x\n",rc
);
999 msiobj_release(&row
->hdr
);
1003 rc
= ACTION_PerformAction(package
,buffer
);
1005 if (rc
== ERROR_FUNCTION_NOT_CALLED
)
1008 if (rc
!= ERROR_SUCCESS
)
1010 ERR("Execution halted due to error (%i)\n",rc
);
1011 msiobj_release(&row
->hdr
);
1015 msiobj_release(&row
->hdr
);
1018 MSI_ViewClose(view
);
1019 msiobj_release(&view
->hdr
);
1026 /********************************************************
1027 * ACTION helper functions and functions that perform the actions
1028 *******************************************************/
1031 * Alot of actions are really important even if they don't do anything
1032 * explicit.. Lots of properties are set at the beginning of the installation
1033 * CostFinalize does a bunch of work to translated the directories and such
1035 * But until I get write access to the database that is hard, so I am going to
1036 * hack it to see if I can get something to run.
1038 UINT
ACTION_PerformAction(MSIPACKAGE
*package
, const WCHAR
*action
)
1040 UINT rc
= ERROR_SUCCESS
;
1042 TRACE("Performing action (%s)\n",debugstr_w(action
));
1043 ui_actioninfo(package
, action
, TRUE
, 0);
1044 ui_actionstart(package
, action
);
1046 /* pre install, setup and configuration block */
1047 if (strcmpW(action
,szLaunchConditions
)==0)
1048 rc
= ACTION_LaunchConditions(package
);
1049 else if (strcmpW(action
,szCostInitialize
)==0)
1050 rc
= ACTION_CostInitialize(package
);
1051 else if (strcmpW(action
,szFileCost
)==0)
1052 rc
= ACTION_FileCost(package
);
1053 else if (strcmpW(action
,szCostFinalize
)==0)
1054 rc
= ACTION_CostFinalize(package
);
1055 else if (strcmpW(action
,szInstallValidate
)==0)
1056 rc
= ACTION_InstallValidate(package
);
1059 else if (strcmpW(action
,szProcessComponents
)==0)
1060 rc
= ACTION_ProcessComponents(package
);
1061 else if (strcmpW(action
,szInstallInitialize
)==0)
1062 rc
= ACTION_InstallInitialize(package
);
1063 else if (strcmpW(action
,szCreateFolders
)==0)
1064 rc
= ACTION_CreateFolders(package
);
1065 else if (strcmpW(action
,szInstallFiles
)==0)
1066 rc
= ACTION_InstallFiles(package
);
1067 else if (strcmpW(action
,szDuplicateFiles
)==0)
1068 rc
= ACTION_DuplicateFiles(package
);
1069 else if (strcmpW(action
,szWriteRegistryValues
)==0)
1070 rc
= ACTION_WriteRegistryValues(package
);
1071 else if (strcmpW(action
,szRegisterTypeLibraries
)==0)
1072 rc
= ACTION_RegisterTypeLibraries(package
);
1073 else if (strcmpW(action
,szRegisterClassInfo
)==0)
1074 rc
= ACTION_RegisterClassInfo(package
);
1075 else if (strcmpW(action
,szRegisterProgIdInfo
)==0)
1076 rc
= ACTION_RegisterProgIdInfo(package
);
1077 else if (strcmpW(action
,szCreateShortcuts
)==0)
1078 rc
= ACTION_CreateShortcuts(package
);
1079 else if (strcmpW(action
,szPublishProduct
)==0)
1080 rc
= ACTION_PublishProduct(package
);
1081 else if (strcmpW(action
,szWriteIniValues
)==0)
1082 rc
= ACTION_WriteIniValues(package
);
1083 else if (strcmpW(action
,szSelfRegModules
)==0)
1084 rc
= ACTION_SelfRegModules(package
);
1085 else if (strcmpW(action
,szPublishFeatures
)==0)
1086 rc
= ACTION_PublishFeatures(package
);
1087 else if (strcmpW(action
,szRegisterProduct
)==0)
1088 rc
= ACTION_RegisterProduct(package
);
1089 else if (strcmpW(action
,szInstallExecute
)==0)
1090 rc
= ACTION_InstallExecute(package
);
1091 else if (strcmpW(action
,szInstallExecuteAgain
)==0)
1092 rc
= ACTION_InstallExecute(package
);
1093 else if (strcmpW(action
,szInstallFinalize
)==0)
1094 rc
= ACTION_InstallFinalize(package
);
1095 else if (strcmpW(action
,szForceReboot
)==0)
1096 rc
= ACTION_ForceReboot(package
);
1099 Called during iTunes but unimplemented and seem important
1101 ResolveSource (sets SourceDir)
1103 else if ((rc
= ACTION_CustomAction(package
,action
,FALSE
)) != ERROR_SUCCESS
)
1105 FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action
));
1106 rc
= ERROR_FUNCTION_NOT_CALLED
;
1109 ui_actioninfo(package
, action
, FALSE
, rc
);
1113 /***********************************************************************
1116 * Recursively create all directories in the path.
1118 * shamelessly stolen from setupapi/queue.c
1120 static BOOL
create_full_pathW(const WCHAR
*path
)
1126 new_path
= HeapAlloc(GetProcessHeap(), 0, (strlenW(path
) + 1) *
1129 strcpyW(new_path
, path
);
1131 while((len
= strlenW(new_path
)) && new_path
[len
- 1] == '\\')
1132 new_path
[len
- 1] = 0;
1134 while(!CreateDirectoryW(new_path
, NULL
))
1137 DWORD last_error
= GetLastError();
1138 if(last_error
== ERROR_ALREADY_EXISTS
)
1141 if(last_error
!= ERROR_PATH_NOT_FOUND
)
1147 if(!(slash
= strrchrW(new_path
, '\\')))
1153 len
= slash
- new_path
;
1155 if(!create_full_pathW(new_path
))
1160 new_path
[len
] = '\\';
1163 HeapFree(GetProcessHeap(), 0, new_path
);
1168 * Also we cannot enable/disable components either, so for now I am just going
1169 * to do all the directories for all the components.
1171 static UINT
ACTION_CreateFolders(MSIPACKAGE
*package
)
1173 static const WCHAR ExecSeqQuery
[] = {
1174 's','e','l','e','c','t',' ','D','i','r','e','c','t','o','r','y','_',' ',
1175 'f','r','o','m',' ','C','r','e','a','t','e','F','o','l','d','e','r',0 };
1180 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1181 if (rc
!= ERROR_SUCCESS
)
1182 return ERROR_SUCCESS
;
1184 rc
= MSI_ViewExecute(view
, 0);
1185 if (rc
!= ERROR_SUCCESS
)
1187 MSI_ViewClose(view
);
1188 msiobj_release(&view
->hdr
);
1197 MSIRECORD
*row
= NULL
, *uirow
;
1199 rc
= MSI_ViewFetch(view
,&row
);
1200 if (rc
!= ERROR_SUCCESS
)
1207 rc
= MSI_RecordGetStringW(row
,1,dir
,&sz
);
1209 if (rc
!= ERROR_SUCCESS
)
1211 ERR("Unable to get folder id \n");
1212 msiobj_release(&row
->hdr
);
1217 full_path
= resolve_folder(package
,dir
,FALSE
,FALSE
,&folder
);
1220 ERR("Unable to resolve folder id %s\n",debugstr_w(dir
));
1221 msiobj_release(&row
->hdr
);
1225 TRACE("Folder is %s\n",debugstr_w(full_path
));
1228 uirow
= MSI_CreateRecord(1);
1229 MSI_RecordSetStringW(uirow
,1,full_path
);
1230 ui_actiondata(package
,szCreateFolders
,uirow
);
1231 msiobj_release( &uirow
->hdr
);
1233 if (folder
->State
== 0)
1234 create_full_pathW(full_path
);
1238 msiobj_release(&row
->hdr
);
1239 HeapFree(GetProcessHeap(),0,full_path
);
1241 MSI_ViewClose(view
);
1242 msiobj_release(&view
->hdr
);
1247 static int load_component(MSIPACKAGE
* package
, MSIRECORD
* row
)
1249 int index
= package
->loaded_components
;
1252 /* fill in the data */
1254 package
->loaded_components
++;
1255 if (package
->loaded_components
== 1)
1256 package
->components
= HeapAlloc(GetProcessHeap(),0,
1257 sizeof(MSICOMPONENT
));
1259 package
->components
= HeapReAlloc(GetProcessHeap(),0,
1260 package
->components
, package
->loaded_components
*
1261 sizeof(MSICOMPONENT
));
1263 memset(&package
->components
[index
],0,sizeof(MSICOMPONENT
));
1266 MSI_RecordGetStringW(row
,1,package
->components
[index
].Component
,&sz
);
1268 TRACE("Loading Component %s\n",
1269 debugstr_w(package
->components
[index
].Component
));
1272 if (!MSI_RecordIsNull(row
,2))
1273 MSI_RecordGetStringW(row
,2,package
->components
[index
].ComponentId
,&sz
);
1276 MSI_RecordGetStringW(row
,3,package
->components
[index
].Directory
,&sz
);
1278 package
->components
[index
].Attributes
= MSI_RecordGetInteger(row
,4);
1281 MSI_RecordGetStringW(row
,5,package
->components
[index
].Condition
,&sz
);
1284 MSI_RecordGetStringW(row
,6,package
->components
[index
].KeyPath
,&sz
);
1286 package
->components
[index
].Installed
= INSTALLSTATE_ABSENT
;
1287 package
->components
[index
].Action
= INSTALLSTATE_UNKNOWN
;
1288 package
->components
[index
].ActionRequest
= INSTALLSTATE_UNKNOWN
;
1290 package
->components
[index
].Enabled
= TRUE
;
1295 static void load_feature(MSIPACKAGE
* package
, MSIRECORD
* row
)
1297 int index
= package
->loaded_features
;
1299 static const WCHAR Query1
[] = {'S','E','L','E','C','T',' ','C','o','m','p',
1300 'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',
1301 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',
1302 'a','t','u','r','e','_','=','\'','%','s','\'',0};
1303 static const WCHAR Query2
[] = {'S','E','L','E','C','T',' ','*',' ','F','R',
1304 'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',
1305 'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};
1312 /* fill in the data */
1314 package
->loaded_features
++;
1315 if (package
->loaded_features
== 1)
1316 package
->features
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE
));
1318 package
->features
= HeapReAlloc(GetProcessHeap(),0,package
->features
,
1319 package
->loaded_features
* sizeof(MSIFEATURE
));
1321 memset(&package
->features
[index
],0,sizeof(MSIFEATURE
));
1324 MSI_RecordGetStringW(row
,1,package
->features
[index
].Feature
,&sz
);
1326 TRACE("Loading feature %s\n",debugstr_w(package
->features
[index
].Feature
));
1329 if (!MSI_RecordIsNull(row
,2))
1330 MSI_RecordGetStringW(row
,2,package
->features
[index
].Feature_Parent
,&sz
);
1333 if (!MSI_RecordIsNull(row
,3))
1334 MSI_RecordGetStringW(row
,3,package
->features
[index
].Title
,&sz
);
1337 if (!MSI_RecordIsNull(row
,4))
1338 MSI_RecordGetStringW(row
,4,package
->features
[index
].Description
,&sz
);
1340 if (!MSI_RecordIsNull(row
,5))
1341 package
->features
[index
].Display
= MSI_RecordGetInteger(row
,5);
1343 package
->features
[index
].Level
= MSI_RecordGetInteger(row
,6);
1346 if (!MSI_RecordIsNull(row
,7))
1347 MSI_RecordGetStringW(row
,7,package
->features
[index
].Directory
,&sz
);
1349 package
->features
[index
].Attributes
= MSI_RecordGetInteger(row
,8);
1351 package
->features
[index
].Installed
= INSTALLSTATE_ABSENT
;
1352 package
->features
[index
].Action
= INSTALLSTATE_UNKNOWN
;
1353 package
->features
[index
].ActionRequest
= INSTALLSTATE_UNKNOWN
;
1355 /* load feature components */
1357 rc
= MSI_OpenQuery(package
->db
, &view
, Query1
, package
->features
[index
].Feature
);
1358 if (rc
!= ERROR_SUCCESS
)
1360 rc
= MSI_ViewExecute(view
,0);
1361 if (rc
!= ERROR_SUCCESS
)
1363 MSI_ViewClose(view
);
1364 msiobj_release(&view
->hdr
);
1370 WCHAR buffer
[0x100];
1373 INT cnt
= package
->features
[index
].ComponentCount
;
1375 rc
= MSI_ViewFetch(view
,&row2
);
1376 if (rc
!= ERROR_SUCCESS
)
1380 MSI_RecordGetStringW(row2
,1,buffer
,&sz
);
1382 /* check to see if the component is already loaded */
1383 c_indx
= get_loaded_component(package
,buffer
);
1386 TRACE("Component %s already loaded at %i\n", debugstr_w(buffer
),
1388 package
->features
[index
].Components
[cnt
] = c_indx
;
1389 package
->features
[index
].ComponentCount
++;
1393 rc
= MSI_OpenQuery(package
->db
, &view2
, Query2
, buffer
);
1394 if (rc
!= ERROR_SUCCESS
)
1396 msiobj_release( &row2
->hdr
);
1399 rc
= MSI_ViewExecute(view2
,0);
1400 if (rc
!= ERROR_SUCCESS
)
1402 msiobj_release( &row2
->hdr
);
1403 MSI_ViewClose(view2
);
1404 msiobj_release( &view2
->hdr
);
1411 rc
= MSI_ViewFetch(view2
,&row3
);
1412 if (rc
!= ERROR_SUCCESS
)
1414 c_indx
= load_component(package
,row3
);
1415 msiobj_release( &row3
->hdr
);
1417 package
->features
[index
].Components
[cnt
] = c_indx
;
1418 package
->features
[index
].ComponentCount
++;
1419 TRACE("Loaded new component to index %i\n",c_indx
);
1421 MSI_ViewClose(view2
);
1422 msiobj_release( &view2
->hdr
);
1423 msiobj_release( &row2
->hdr
);
1425 MSI_ViewClose(view
);
1426 msiobj_release(&view
->hdr
);
1430 * I am not doing any of the costing functionality yet.
1431 * Mostly looking at doing the Component and Feature loading
1433 * The native MSI does ALOT of modification to tables here. Mostly adding alot
1434 * of temporary columns to the Feature and Component tables.
1436 * note: native msi also tracks the short filename. but I am only going to
1437 * track the long ones. Also looking at this directory table
1438 * it appears that the directory table does not get the parents
1439 * resolved base on property only based on their entrys in the
1442 static UINT
ACTION_CostInitialize(MSIPACKAGE
*package
)
1447 static const WCHAR Query_all
[] = {
1448 'S','E','L','E','C','T',' ','*',' ',
1449 'F','R','O','M',' ','F','e','a','t','u','r','e',0};
1450 static const WCHAR szCosting
[] = {
1451 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1452 static const WCHAR szZero
[] = { '0', 0 };
1454 MSI_SetPropertyW(package
, szCosting
, szZero
);
1455 MSI_SetPropertyW(package
, cszRootDrive
, c_collen
);
1457 rc
= MSI_DatabaseOpenViewW(package
->db
,Query_all
,&view
);
1458 if (rc
!= ERROR_SUCCESS
)
1460 rc
= MSI_ViewExecute(view
,0);
1461 if (rc
!= ERROR_SUCCESS
)
1463 MSI_ViewClose(view
);
1464 msiobj_release(&view
->hdr
);
1471 rc
= MSI_ViewFetch(view
,&row
);
1472 if (rc
!= ERROR_SUCCESS
)
1475 load_feature(package
,row
);
1476 msiobj_release(&row
->hdr
);
1478 MSI_ViewClose(view
);
1479 msiobj_release(&view
->hdr
);
1481 return ERROR_SUCCESS
;
1484 static UINT
load_file(MSIPACKAGE
* package
, MSIRECORD
* row
)
1486 DWORD index
= package
->loaded_files
;
1490 /* fill in the data */
1492 package
->loaded_files
++;
1493 if (package
->loaded_files
== 1)
1494 package
->files
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE
));
1496 package
->files
= HeapReAlloc(GetProcessHeap(),0,
1497 package
->files
, package
->loaded_files
* sizeof(MSIFILE
));
1499 memset(&package
->files
[index
],0,sizeof(MSIFILE
));
1501 package
->files
[index
].File
= load_dynamic_stringW(row
, 1);
1502 buffer
= load_dynamic_stringW(row
, 2);
1504 package
->files
[index
].ComponentIndex
= -1;
1505 for (i
= 0; i
< package
->loaded_components
; i
++)
1506 if (strcmpW(package
->components
[i
].Component
,buffer
)==0)
1508 package
->files
[index
].ComponentIndex
= i
;
1511 if (package
->files
[index
].ComponentIndex
== -1)
1512 ERR("Unfound Component %s\n",debugstr_w(buffer
));
1513 HeapFree(GetProcessHeap(), 0, buffer
);
1515 package
->files
[index
].FileName
= load_dynamic_stringW(row
,3);
1517 reduce_to_longfilename(package
->files
[index
].FileName
);
1519 package
->files
[index
].FileSize
= MSI_RecordGetInteger(row
,4);
1520 package
->files
[index
].Version
= load_dynamic_stringW(row
, 5);
1521 package
->files
[index
].Language
= load_dynamic_stringW(row
, 6);
1522 package
->files
[index
].Attributes
= MSI_RecordGetInteger(row
,7);
1523 package
->files
[index
].Sequence
= MSI_RecordGetInteger(row
,8);
1525 package
->files
[index
].Temporary
= FALSE
;
1526 package
->files
[index
].State
= 0;
1528 TRACE("File Loaded (%s)\n",debugstr_w(package
->files
[index
].File
));
1530 return ERROR_SUCCESS
;
1533 static UINT
ACTION_FileCost(MSIPACKAGE
*package
)
1538 static const WCHAR Query
[] = {
1539 'S','E','L','E','C','T',' ','*',' ',
1540 'F','R','O','M',' ','F','i','l','e',' ',
1541 'O','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e', 0};
1544 return ERROR_INVALID_HANDLE
;
1546 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
1547 if (rc
!= ERROR_SUCCESS
)
1548 return ERROR_SUCCESS
;
1550 rc
= MSI_ViewExecute(view
, 0);
1551 if (rc
!= ERROR_SUCCESS
)
1553 MSI_ViewClose(view
);
1554 msiobj_release(&view
->hdr
);
1555 return ERROR_SUCCESS
;
1560 rc
= MSI_ViewFetch(view
,&row
);
1561 if (rc
!= ERROR_SUCCESS
)
1566 load_file(package
,row
);
1567 msiobj_release(&row
->hdr
);
1569 MSI_ViewClose(view
);
1570 msiobj_release(&view
->hdr
);
1572 return ERROR_SUCCESS
;
1575 static INT
load_folder(MSIPACKAGE
*package
, const WCHAR
* dir
)
1578 static const WCHAR Query
[] =
1579 {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',
1580 't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',
1581 'o','r','y','`',' ','=',' ','`','%','s','`',0};
1584 LPWSTR targetdir
, parent
, srcdir
;
1585 MSIRECORD
* row
= 0;
1589 TRACE("Looking for dir %s\n",debugstr_w(dir
));
1591 for (i
= 0; i
< package
->loaded_folders
; i
++)
1593 if (strcmpW(package
->folders
[i
].Directory
,dir
)==0)
1595 TRACE(" %s retuning on index %lu\n",debugstr_w(dir
),i
);
1600 TRACE("Working to load %s\n",debugstr_w(dir
));
1602 index
= package
->loaded_folders
++;
1603 if (package
->loaded_folders
==1)
1604 package
->folders
= HeapAlloc(GetProcessHeap(),0,
1607 package
->folders
= HeapReAlloc(GetProcessHeap(),0,
1608 package
->folders
, package
->loaded_folders
*
1611 memset(&package
->folders
[index
],0,sizeof(MSIFOLDER
));
1613 package
->folders
[index
].Directory
= dupstrW(dir
);
1615 rc
= MSI_OpenQuery(package
->db
, &view
, Query
, dir
);
1616 if (rc
!= ERROR_SUCCESS
)
1619 rc
= MSI_ViewExecute(view
, 0);
1620 if (rc
!= ERROR_SUCCESS
)
1622 MSI_ViewClose(view
);
1623 msiobj_release(&view
->hdr
);
1627 rc
= MSI_ViewFetch(view
,&row
);
1628 if (rc
!= ERROR_SUCCESS
)
1630 MSI_ViewClose(view
);
1631 msiobj_release(&view
->hdr
);
1635 targetdir
= load_dynamic_stringW(row
,3);
1637 /* split src and target dir */
1638 if (strchrW(targetdir
,':'))
1640 srcdir
=strchrW(targetdir
,':');
1647 /* for now only pick long filename versions */
1648 if (strchrW(targetdir
,'|'))
1650 targetdir
= strchrW(targetdir
,'|');
1654 if (srcdir
&& strchrW(srcdir
,'|'))
1656 srcdir
= strchrW(srcdir
,'|');
1661 /* now check for root dirs */
1662 if (targetdir
[0] == '.' && targetdir
[1] == 0)
1665 if (srcdir
&& srcdir
[0] == '.' && srcdir
[1] == 0)
1670 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir
));
1671 HeapFree(GetProcessHeap(),0, package
->folders
[index
].TargetDefault
);
1672 package
->folders
[index
].TargetDefault
= dupstrW(targetdir
);
1676 package
->folders
[index
].SourceDefault
= dupstrW(srcdir
);
1678 package
->folders
[index
].SourceDefault
= dupstrW(targetdir
);
1679 HeapFree(GetProcessHeap(), 0, targetdir
);
1681 parent
= load_dynamic_stringW(row
,2);
1684 i
= load_folder(package
,parent
);
1685 package
->folders
[index
].ParentIndex
= i
;
1686 TRACE("Parent is index %i... %s %s\n",
1687 package
->folders
[index
].ParentIndex
,
1688 debugstr_w(package
->folders
[package
->folders
[index
].ParentIndex
].Directory
),
1689 debugstr_w(parent
));
1692 package
->folders
[index
].ParentIndex
= -2;
1693 HeapFree(GetProcessHeap(), 0, parent
);
1695 package
->folders
[index
].Property
= load_dynamic_property(package
, dir
,NULL
);
1697 msiobj_release(&row
->hdr
);
1698 MSI_ViewClose(view
);
1699 msiobj_release(&view
->hdr
);
1700 TRACE(" %s retuning on index %i\n",debugstr_w(dir
),index
);
1705 LPWSTR
resolve_folder(MSIPACKAGE
*package
, LPCWSTR name
, BOOL source
,
1706 BOOL set_prop
, MSIFOLDER
**folder
)
1709 LPWSTR p
, path
= NULL
;
1711 TRACE("Working to resolve %s\n",debugstr_w(name
));
1713 /* special resolving for Target and Source root dir */
1714 if (strcmpW(name
,cszTargetDir
)==0 || strcmpW(name
,cszSourceDir
)==0)
1718 path
= load_dynamic_property(package
,cszTargetDir
,NULL
);
1721 path
= load_dynamic_property(package
,cszRootDrive
,NULL
);
1723 MSI_SetPropertyW(package
,cszTargetDir
,path
);
1727 for (i
= 0; i
< package
->loaded_folders
; i
++)
1729 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
1732 *folder
= &(package
->folders
[i
]);
1738 path
= load_dynamic_property(package
,cszSourceDir
,NULL
);
1741 path
= load_dynamic_property(package
,cszDatabase
,NULL
);
1744 p
= strrchrW(path
,'\\');
1751 for (i
= 0; i
< package
->loaded_folders
; i
++)
1753 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
1756 *folder
= &(package
->folders
[i
]);
1762 for (i
= 0; i
< package
->loaded_folders
; i
++)
1764 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
1768 if (i
>= package
->loaded_folders
)
1772 *folder
= &(package
->folders
[i
]);
1774 if (!source
&& package
->folders
[i
].ResolvedTarget
)
1776 path
= dupstrW(package
->folders
[i
].ResolvedTarget
);
1777 TRACE(" already resolved to %s\n",debugstr_w(path
));
1780 else if (source
&& package
->folders
[i
].ResolvedSource
)
1782 path
= dupstrW(package
->folders
[i
].ResolvedSource
);
1785 else if (!source
&& package
->folders
[i
].Property
)
1787 path
= dupstrW(package
->folders
[i
].Property
);
1788 TRACE(" internally set to %s\n",debugstr_w(path
));
1790 MSI_SetPropertyW(package
,name
,path
);
1794 if (package
->folders
[i
].ParentIndex
>= 0)
1796 LPWSTR parent
= package
->folders
[package
->folders
[i
].ParentIndex
].Directory
;
1798 TRACE(" ! Parent is %s\n", debugstr_w(parent
));
1800 p
= resolve_folder(package
, parent
, source
, set_prop
, NULL
);
1803 TRACE(" TargetDefault = %s\n",debugstr_w(package
->folders
[i
].TargetDefault
));
1804 path
= build_directory_name(3, p
, package
->folders
[i
].TargetDefault
, NULL
);
1805 package
->folders
[i
].ResolvedTarget
= dupstrW(path
);
1806 TRACE(" resolved into %s\n",debugstr_w(path
));
1808 MSI_SetPropertyW(package
,name
,path
);
1812 path
= build_directory_name(3, p
, package
->folders
[i
].SourceDefault
, NULL
);
1813 package
->folders
[i
].ResolvedSource
= dupstrW(path
);
1815 HeapFree(GetProcessHeap(),0,p
);
1820 static UINT
SetFeatureStates(MSIPACKAGE
*package
)
1826 LPWSTR override
= NULL
;
1827 static const WCHAR all
[]={'A','L','L',0};
1828 static const WCHAR szlevel
[] = {
1829 'I','N','S','T','A','L','L','L','E','V','E','L',0};
1830 static const WCHAR szAddLocal
[] = {
1831 'A','D','D','L','O','C','A','L',0};
1833 /* I do not know if this is where it should happen.. but */
1835 TRACE("Checking Install Level\n");
1837 level
= load_dynamic_property(package
,szlevel
,NULL
);
1840 install_level
= atoiW(level
);
1841 HeapFree(GetProcessHeap(), 0, level
);
1846 /* ok hereis the rub
1847 * ADDLOCAL and its friend OVERRIDE INSTALLLEVLE
1848 * I have confirmed this if ADDLOCALis stated then the INSTALLLEVEL is
1849 * itnored for all the features. seems strange, epsecially since it is not
1850 * documented anywhere, but it is how it works.
1853 override
= load_dynamic_property(package
,szAddLocal
,NULL
);
1857 for(i
= 0; i
< package
->loaded_features
; i
++)
1859 if (strcmpiW(override
,all
)==0)
1861 package
->features
[i
].ActionRequest
= INSTALLSTATE_LOCAL
;
1862 package
->features
[i
].Action
= INSTALLSTATE_LOCAL
;
1866 LPWSTR ptr
= override
;
1867 LPWSTR ptr2
= strchrW(override
,',');
1872 strncmpW(ptr
,package
->features
[i
].Feature
, ptr2
-ptr
)==0)
1874 strcmpW(ptr
,package
->features
[i
].Feature
)==0))
1876 package
->features
[i
].ActionRequest
= INSTALLSTATE_LOCAL
;
1877 package
->features
[i
].Action
= INSTALLSTATE_LOCAL
;
1883 ptr2
= strchrW(ptr
,',');
1890 HeapFree(GetProcessHeap(),0,override
);
1894 for(i
= 0; i
< package
->loaded_features
; i
++)
1896 BOOL feature_state
= ((package
->features
[i
].Level
> 0) &&
1897 (package
->features
[i
].Level
<= install_level
));
1901 package
->features
[i
].ActionRequest
= INSTALLSTATE_LOCAL
;
1902 package
->features
[i
].Action
= INSTALLSTATE_LOCAL
;
1908 * now we want to enable or disable components base on feature
1911 for(i
= 0; i
< package
->loaded_features
; i
++)
1913 MSIFEATURE
* feature
= &package
->features
[i
];
1914 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1915 debugstr_w(feature
->Feature
), feature
->Installed
, feature
->Action
,
1916 feature
->ActionRequest
);
1918 for( j
= 0; j
< feature
->ComponentCount
; j
++)
1920 MSICOMPONENT
* component
= &package
->components
[
1921 feature
->Components
[j
]];
1923 if (!component
->Enabled
)
1925 component
->Action
= INSTALLSTATE_ABSENT
;
1926 component
->ActionRequest
= INSTALLSTATE_ABSENT
;
1930 if (feature
->Action
== INSTALLSTATE_LOCAL
)
1931 component
->Action
= INSTALLSTATE_LOCAL
;
1932 if (feature
->ActionRequest
== INSTALLSTATE_LOCAL
)
1933 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
1938 for(i
= 0; i
< package
->loaded_components
; i
++)
1940 MSICOMPONENT
* component
= &package
->components
[i
];
1942 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1943 debugstr_w(component
->Component
), component
->Installed
,
1944 component
->Action
, component
->ActionRequest
);
1948 return ERROR_SUCCESS
;
1952 * Alot is done in this function aside from just the costing.
1953 * The costing needs to be implemented at some point but for now I am going
1954 * to focus on the directory building
1957 static UINT
ACTION_CostFinalize(MSIPACKAGE
*package
)
1959 static const WCHAR ExecSeqQuery
[] = {
1960 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
1961 'D','i','r','e','c','t','o','r','y',0};
1962 static const WCHAR ConditionQuery
[] = {
1963 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
1964 'C','o','n','d','i','t','i','o','n',0};
1965 static const WCHAR szCosting
[] = {
1966 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1967 static const WCHAR szlevel
[] = {
1968 'I','N','S','T','A','L','L','L','E','V','E','L',0};
1969 static const WCHAR szOne
[] = { '1', 0 };
1975 TRACE("Building Directory properties\n");
1977 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
1978 if (rc
== ERROR_SUCCESS
)
1980 rc
= MSI_ViewExecute(view
, 0);
1981 if (rc
!= ERROR_SUCCESS
)
1983 MSI_ViewClose(view
);
1984 msiobj_release(&view
->hdr
);
1992 MSIRECORD
* row
= 0;
1995 rc
= MSI_ViewFetch(view
,&row
);
1996 if (rc
!= ERROR_SUCCESS
)
2003 MSI_RecordGetStringW(row
,1,name
,&sz
);
2005 /* This helper function now does ALL the work */
2006 TRACE("Dir %s ...\n",debugstr_w(name
));
2007 load_folder(package
,name
);
2008 path
= resolve_folder(package
,name
,FALSE
,TRUE
,NULL
);
2009 TRACE("resolves to %s\n",debugstr_w(path
));
2010 HeapFree( GetProcessHeap(), 0, path
);
2012 msiobj_release(&row
->hdr
);
2014 MSI_ViewClose(view
);
2015 msiobj_release(&view
->hdr
);
2018 TRACE("File calculations %i files\n",package
->loaded_files
);
2020 for (i
= 0; i
< package
->loaded_files
; i
++)
2022 MSICOMPONENT
* comp
= NULL
;
2023 MSIFILE
* file
= NULL
;
2025 file
= &package
->files
[i
];
2026 if (file
->ComponentIndex
>= 0)
2027 comp
= &package
->components
[file
->ComponentIndex
];
2029 if (file
->Temporary
== TRUE
)
2036 /* calculate target */
2037 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, NULL
);
2039 HeapFree(GetProcessHeap(),0,file
->TargetPath
);
2041 TRACE("file %s is named %s\n",
2042 debugstr_w(file
->File
),debugstr_w(file
->FileName
));
2044 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
2046 HeapFree(GetProcessHeap(),0,p
);
2048 TRACE("file %s resolves to %s\n",
2049 debugstr_w(file
->File
),debugstr_w(file
->TargetPath
));
2051 if (GetFileAttributesW(file
->TargetPath
) == INVALID_FILE_ATTRIBUTES
)
2054 comp
->Cost
+= file
->FileSize
;
2064 static const WCHAR name
[] =
2066 static const WCHAR name_fmt
[] =
2067 {'%','u','.','%','u','.','%','u','.','%','u',0};
2068 WCHAR filever
[0x100];
2069 VS_FIXEDFILEINFO
*lpVer
;
2071 TRACE("Version comparison.. \n");
2072 versize
= GetFileVersionInfoSizeW(file
->TargetPath
,&handle
);
2073 version
= HeapAlloc(GetProcessHeap(),0,versize
);
2074 GetFileVersionInfoW(file
->TargetPath
, 0, versize
, version
);
2076 VerQueryValueW(version
, name
, (LPVOID
*)&lpVer
, &sz
);
2078 sprintfW(filever
,name_fmt
,
2079 HIWORD(lpVer
->dwFileVersionMS
),
2080 LOWORD(lpVer
->dwFileVersionMS
),
2081 HIWORD(lpVer
->dwFileVersionLS
),
2082 LOWORD(lpVer
->dwFileVersionLS
));
2084 TRACE("new %s old %s\n", debugstr_w(file
->Version
),
2085 debugstr_w(filever
));
2086 if (strcmpiW(filever
,file
->Version
)<0)
2089 FIXME("cost should be diff in size\n");
2090 comp
->Cost
+= file
->FileSize
;
2094 HeapFree(GetProcessHeap(),0,version
);
2102 TRACE("Evaluating Condition Table\n");
2104 rc
= MSI_DatabaseOpenViewW(package
->db
, ConditionQuery
, &view
);
2105 if (rc
== ERROR_SUCCESS
)
2107 rc
= MSI_ViewExecute(view
, 0);
2108 if (rc
!= ERROR_SUCCESS
)
2110 MSI_ViewClose(view
);
2111 msiobj_release(&view
->hdr
);
2117 WCHAR Feature
[0x100];
2118 MSIRECORD
* row
= 0;
2122 rc
= MSI_ViewFetch(view
,&row
);
2124 if (rc
!= ERROR_SUCCESS
)
2131 MSI_RecordGetStringW(row
,1,Feature
,&sz
);
2133 feature_index
= get_loaded_feature(package
,Feature
);
2134 if (feature_index
< 0)
2135 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature
));
2139 Condition
= load_dynamic_stringW(row
,3);
2141 if (MSI_EvaluateConditionW(package
,Condition
) ==
2144 int level
= MSI_RecordGetInteger(row
,2);
2145 TRACE("Reseting feature %s to level %i\n",
2146 debugstr_w(Feature
), level
);
2147 package
->features
[feature_index
].Level
= level
;
2149 HeapFree(GetProcessHeap(),0,Condition
);
2152 msiobj_release(&row
->hdr
);
2154 MSI_ViewClose(view
);
2155 msiobj_release(&view
->hdr
);
2158 TRACE("Enabling or Disabling Components\n");
2159 for (i
= 0; i
< package
->loaded_components
; i
++)
2161 if (package
->components
[i
].Condition
[0])
2163 if (MSI_EvaluateConditionW(package
,
2164 package
->components
[i
].Condition
) == MSICONDITION_FALSE
)
2166 TRACE("Disabling component %s\n",
2167 debugstr_w(package
->components
[i
].Component
));
2168 package
->components
[i
].Enabled
= FALSE
;
2173 MSI_SetPropertyW(package
,szCosting
,szOne
);
2174 /* set default run level if not set */
2175 level
= load_dynamic_property(package
,szlevel
,NULL
);
2177 MSI_SetPropertyW(package
,szlevel
, szOne
);
2179 HeapFree(GetProcessHeap(),0,level
);
2181 return SetFeatureStates(package
);
2186 * This is a helper function for handling embedded cabinet media
2188 static UINT
writeout_cabinet_stream(MSIPACKAGE
*package
, WCHAR
* stream_name
,
2196 WCHAR tmp
[MAX_PATH
];
2198 rc
= read_raw_stream_data(package
->db
,stream_name
,&data
,&size
);
2199 if (rc
!= ERROR_SUCCESS
)
2203 if (MSI_GetPropertyW(package
, cszTempFolder
, tmp
, &write
))
2204 GetTempPathW(MAX_PATH
,tmp
);
2206 GetTempFileNameW(tmp
,stream_name
,0,source
);
2208 track_tempfile(package
,strrchrW(source
,'\\'), source
);
2209 the_file
= CreateFileW(source
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
2210 FILE_ATTRIBUTE_NORMAL
, NULL
);
2212 if (the_file
== INVALID_HANDLE_VALUE
)
2214 rc
= ERROR_FUNCTION_FAILED
;
2218 WriteFile(the_file
,data
,size
,&write
,NULL
);
2219 CloseHandle(the_file
);
2220 TRACE("wrote %li bytes to %s\n",write
,debugstr_w(source
));
2222 HeapFree(GetProcessHeap(),0,data
);
2227 /* Support functions for FDI functions */
2230 MSIPACKAGE
* package
;
2235 static void * cabinet_alloc(ULONG cb
)
2237 return HeapAlloc(GetProcessHeap(), 0, cb
);
2240 static void cabinet_free(void *pv
)
2242 HeapFree(GetProcessHeap(), 0, pv
);
2245 static INT_PTR
cabinet_open(char *pszFile
, int oflag
, int pmode
)
2248 DWORD dwShareMode
= 0;
2249 DWORD dwCreateDisposition
= OPEN_EXISTING
;
2250 switch (oflag
& _O_ACCMODE
)
2253 dwAccess
= GENERIC_READ
;
2254 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_DELETE
;
2257 dwAccess
= GENERIC_WRITE
;
2258 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
2261 dwAccess
= GENERIC_READ
| GENERIC_WRITE
;
2262 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
2265 if ((oflag
& (_O_CREAT
| _O_EXCL
)) == (_O_CREAT
| _O_EXCL
))
2266 dwCreateDisposition
= CREATE_NEW
;
2267 else if (oflag
& _O_CREAT
)
2268 dwCreateDisposition
= CREATE_ALWAYS
;
2269 return (INT_PTR
)CreateFileA(pszFile
, dwAccess
, dwShareMode
, NULL
, dwCreateDisposition
, 0, NULL
);
2272 static UINT
cabinet_read(INT_PTR hf
, void *pv
, UINT cb
)
2275 if (ReadFile((HANDLE
)hf
, pv
, cb
, &dwRead
, NULL
))
2280 static UINT
cabinet_write(INT_PTR hf
, void *pv
, UINT cb
)
2283 if (WriteFile((HANDLE
)hf
, pv
, cb
, &dwWritten
, NULL
))
2288 static int cabinet_close(INT_PTR hf
)
2290 return CloseHandle((HANDLE
)hf
) ? 0 : -1;
2293 static long cabinet_seek(INT_PTR hf
, long dist
, int seektype
)
2295 /* flags are compatible and so are passed straight through */
2296 return SetFilePointer((HANDLE
)hf
, dist
, NULL
, seektype
);
2299 static INT_PTR
cabinet_notify(FDINOTIFICATIONTYPE fdint
, PFDINOTIFICATION pfdin
)
2301 /* FIXME: try to do more processing in this function */
2304 case fdintCOPY_FILE
:
2306 CabData
*data
= (CabData
*) pfdin
->pv
;
2307 ULONG len
= strlen(data
->cab_path
) + strlen(pfdin
->psz1
);
2312 LPWSTR tracknametmp
;
2313 static const WCHAR tmpprefix
[] = {'C','A','B','T','M','P','_',0};
2315 if (data
->file_name
&& strcmp(data
->file_name
,pfdin
->psz1
))
2318 file
= cabinet_alloc((len
+1)*sizeof(char));
2319 strcpy(file
, data
->cab_path
);
2320 strcat(file
, pfdin
->psz1
);
2322 TRACE("file: %s\n", debugstr_a(file
));
2324 /* track this file so it can be deleted if not installed */
2325 trackpath
=strdupAtoW(file
);
2326 tracknametmp
=strdupAtoW(strrchr(file
,'\\')+1);
2327 trackname
= HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp
) +
2328 strlenW(tmpprefix
)+1) * sizeof(WCHAR
));
2330 strcpyW(trackname
,tmpprefix
);
2331 strcatW(trackname
,tracknametmp
);
2333 track_tempfile(data
->package
, trackname
, trackpath
);
2335 HeapFree(GetProcessHeap(),0,trackpath
);
2336 HeapFree(GetProcessHeap(),0,trackname
);
2337 HeapFree(GetProcessHeap(),0,tracknametmp
);
2339 return cabinet_open(file
, _O_WRONLY
| _O_CREAT
, 0);
2341 case fdintCLOSE_FILE_INFO
:
2345 if (!DosDateTimeToFileTime(pfdin
->date
, pfdin
->time
, &ft
))
2347 if (!LocalFileTimeToFileTime(&ft
, &ftLocal
))
2349 if (!SetFileTime((HANDLE
)pfdin
->hf
, &ftLocal
, 0, &ftLocal
))
2352 cabinet_close(pfdin
->hf
);
2360 /***********************************************************************
2361 * extract_cabinet_file
2363 * Extract files from a cab file.
2365 static BOOL
extract_a_cabinet_file(MSIPACKAGE
* package
, const WCHAR
* source
,
2366 const WCHAR
* path
, const WCHAR
* file
)
2376 TRACE("Extracting %s (%s) to %s\n",debugstr_w(source
),
2377 debugstr_w(file
), debugstr_w(path
));
2379 hfdi
= FDICreate(cabinet_alloc
,
2390 ERR("FDICreate failed\n");
2394 if (!(cabinet
= strdupWtoA( source
)))
2399 if (!(cab_path
= strdupWtoA( path
)))
2402 HeapFree(GetProcessHeap(), 0, cabinet
);
2406 data
.package
= package
;
2407 data
.cab_path
= cab_path
;
2409 file_name
= strdupWtoA(file
);
2412 data
.file_name
= file_name
;
2414 ret
= FDICopy(hfdi
, cabinet
, "", 0, cabinet_notify
, NULL
, &data
);
2417 ERR("FDICopy failed\n");
2421 HeapFree(GetProcessHeap(), 0, cabinet
);
2422 HeapFree(GetProcessHeap(), 0, cab_path
);
2423 HeapFree(GetProcessHeap(), 0, file_name
);
2428 static UINT
ready_media_for_file(MSIPACKAGE
*package
, UINT sequence
,
2429 WCHAR
* path
, WCHAR
* file
)
2433 MSIRECORD
* row
= 0;
2434 static WCHAR source
[MAX_PATH
];
2435 static const WCHAR ExecSeqQuery
[] = {
2436 's','e','l','e','c','t',' ','*',' ',
2437 'f','r','o','m',' ','M','e','d','i','a',' ',
2438 'w','h','e','r','e',' ','L','a','s','t','S','e','q','u','e','n','c','e',' ','>','=',' ','%','i',' ',
2439 'o','r','d','e','r',' ','b','y',' ','L','a','s','t','S','e','q','u','e','n','c','e',0};
2444 static UINT last_sequence
= 0;
2446 if (sequence
<= last_sequence
)
2448 TRACE("Media already ready (%u, %u)\n",sequence
,last_sequence
);
2449 /*extract_a_cabinet_file(package, source,path,file); */
2450 return ERROR_SUCCESS
;
2453 sprintfW(Query
,ExecSeqQuery
,sequence
);
2455 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
2456 if (rc
!= ERROR_SUCCESS
)
2459 rc
= MSI_ViewExecute(view
, 0);
2460 if (rc
!= ERROR_SUCCESS
)
2462 MSI_ViewClose(view
);
2463 msiobj_release(&view
->hdr
);
2467 rc
= MSI_ViewFetch(view
,&row
);
2468 if (rc
!= ERROR_SUCCESS
)
2470 MSI_ViewClose(view
);
2471 msiobj_release(&view
->hdr
);
2474 seq
= MSI_RecordGetInteger(row
,2);
2475 last_sequence
= seq
;
2477 if (!MSI_RecordIsNull(row
,4))
2480 MSI_RecordGetStringW(row
,4,cab
,&sz
);
2481 TRACE("Source is CAB %s\n",debugstr_w(cab
));
2482 /* the stream does not contain the # character */
2485 writeout_cabinet_stream(package
,&cab
[1],source
);
2486 strcpyW(path
,source
);
2487 *(strrchrW(path
,'\\')+1)=0;
2492 if (MSI_GetPropertyW(package
, cszSourceDir
, source
, &sz
))
2494 ERR("No Source dir defined \n");
2495 rc
= ERROR_FUNCTION_FAILED
;
2499 strcpyW(path
,source
);
2500 strcatW(source
,cab
);
2501 /* extract the cab file into a folder in the temp folder */
2503 if (MSI_GetPropertyW(package
, cszTempFolder
,path
, &sz
)
2505 GetTempPathW(MAX_PATH
,path
);
2508 rc
= !extract_a_cabinet_file(package
, source
,path
,NULL
);
2510 msiobj_release(&row
->hdr
);
2511 MSI_ViewClose(view
);
2512 msiobj_release(&view
->hdr
);
2516 inline static UINT
create_component_directory ( MSIPACKAGE
* package
, INT component
)
2518 UINT rc
= ERROR_SUCCESS
;
2520 LPWSTR install_path
;
2522 install_path
= resolve_folder(package
, package
->components
[component
].Directory
,
2523 FALSE
, FALSE
, &folder
);
2525 return ERROR_FUNCTION_FAILED
;
2527 /* create the path */
2528 if (folder
->State
== 0)
2530 create_full_pathW(install_path
);
2533 HeapFree(GetProcessHeap(), 0, install_path
);
2538 static UINT
ACTION_InstallFiles(MSIPACKAGE
*package
)
2540 UINT rc
= ERROR_SUCCESS
;
2543 WCHAR uipath
[MAX_PATH
];
2546 return ERROR_INVALID_HANDLE
;
2548 /* increment progress bar each time action data is sent */
2549 ui_progress(package
,1,1,0,0);
2551 for (index
= 0; index
< package
->loaded_files
; index
++)
2553 WCHAR path_to_source
[MAX_PATH
];
2556 file
= &package
->files
[index
];
2558 if (file
->Temporary
)
2561 if (package
->components
[file
->ComponentIndex
].ActionRequest
!=
2564 ui_progress(package
,2,file
->FileSize
,0,0);
2565 TRACE("File %s is not scheduled for install\n",
2566 debugstr_w(file
->File
));
2571 if ((file
->State
== 1) || (file
->State
== 2))
2575 MSICOMPONENT
* comp
= NULL
;
2577 TRACE("Installing %s\n",debugstr_w(file
->File
));
2578 rc
= ready_media_for_file(package
,file
->Sequence
,path_to_source
,
2582 * our file table could change here because a new temp file
2583 * may have been created
2585 file
= &package
->files
[index
];
2586 if (rc
!= ERROR_SUCCESS
)
2588 ERR("Unable to ready media\n");
2589 rc
= ERROR_FUNCTION_FAILED
;
2593 create_component_directory( package
, file
->ComponentIndex
);
2595 /* recalculate file paths because things may have changed */
2597 if (file
->ComponentIndex
>= 0)
2598 comp
= &package
->components
[file
->ComponentIndex
];
2600 p
= resolve_folder(package
, comp
->Directory
, FALSE
, FALSE
, NULL
);
2601 HeapFree(GetProcessHeap(),0,file
->TargetPath
);
2603 file
->TargetPath
= build_directory_name(2, p
, file
->FileName
);
2605 len
= strlenW(path_to_source
) + strlenW(file
->File
) + 2;
2606 file
->SourcePath
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
2607 strcpyW(file
->SourcePath
, path_to_source
);
2608 strcatW(file
->SourcePath
, file
->File
);
2610 TRACE("file paths %s to %s\n",debugstr_w(file
->SourcePath
),
2611 debugstr_w(file
->TargetPath
));
2614 uirow
=MSI_CreateRecord(9);
2615 MSI_RecordSetStringW(uirow
,1,file
->File
);
2616 strcpyW(uipath
,file
->TargetPath
);
2617 *(strrchrW(uipath
,'\\')+1)=0;
2618 MSI_RecordSetStringW(uirow
,9,uipath
);
2619 MSI_RecordSetInteger(uirow
,6,file
->FileSize
);
2620 ui_actiondata(package
,szInstallFiles
,uirow
);
2621 msiobj_release( &uirow
->hdr
);
2622 ui_progress(package
,2,file
->FileSize
,0,0);
2624 if (!MoveFileW(file
->SourcePath
,file
->TargetPath
))
2626 rc
= GetLastError();
2627 ERR("Unable to move file (%s -> %s) (error %d)\n",
2628 debugstr_w(file
->SourcePath
), debugstr_w(file
->TargetPath
),
2630 if (rc
== ERROR_ALREADY_EXISTS
&& file
->State
== 2)
2632 CopyFileW(file
->SourcePath
,file
->TargetPath
,FALSE
);
2633 DeleteFileW(file
->SourcePath
);
2636 else if (rc
== ERROR_FILE_NOT_FOUND
)
2638 ERR("Source File Not Found! Continueing\n");
2643 ERR("Ignoring Error and continuing...\n");
2655 inline static UINT
get_file_target(MSIPACKAGE
*package
, LPCWSTR file_key
,
2656 LPWSTR
* file_source
)
2661 return ERROR_INVALID_HANDLE
;
2663 for (index
= 0; index
< package
->loaded_files
; index
++)
2665 if (strcmpW(file_key
,package
->files
[index
].File
)==0)
2667 if (package
->files
[index
].State
>= 2)
2669 *file_source
= dupstrW(package
->files
[index
].TargetPath
);
2670 return ERROR_SUCCESS
;
2673 return ERROR_FILE_NOT_FOUND
;
2677 return ERROR_FUNCTION_FAILED
;
2680 static UINT
ACTION_DuplicateFiles(MSIPACKAGE
*package
)
2684 MSIRECORD
* row
= 0;
2685 static const WCHAR ExecSeqQuery
[] = {
2686 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',
2687 'D','u','p','l','i','c','a','t','e','F','i','l','e',0};
2690 return ERROR_INVALID_HANDLE
;
2692 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2693 if (rc
!= ERROR_SUCCESS
)
2694 return ERROR_SUCCESS
;
2696 rc
= MSI_ViewExecute(view
, 0);
2697 if (rc
!= ERROR_SUCCESS
)
2699 MSI_ViewClose(view
);
2700 msiobj_release(&view
->hdr
);
2706 WCHAR file_key
[0x100];
2707 WCHAR
*file_source
= NULL
;
2708 WCHAR dest_name
[0x100];
2709 LPWSTR dest_path
, dest
;
2710 WCHAR component
[0x100];
2711 INT component_index
;
2715 rc
= MSI_ViewFetch(view
,&row
);
2716 if (rc
!= ERROR_SUCCESS
)
2723 rc
= MSI_RecordGetStringW(row
,2,component
,&sz
);
2724 if (rc
!= ERROR_SUCCESS
)
2726 ERR("Unable to get component\n");
2727 msiobj_release(&row
->hdr
);
2731 component_index
= get_loaded_component(package
,component
);
2732 if (package
->components
[component_index
].ActionRequest
!=
2735 TRACE("Skipping copy due to disabled component\n");
2736 msiobj_release(&row
->hdr
);
2741 rc
= MSI_RecordGetStringW(row
,3,file_key
,&sz
);
2742 if (rc
!= ERROR_SUCCESS
)
2744 ERR("Unable to get file key\n");
2745 msiobj_release(&row
->hdr
);
2749 rc
= get_file_target(package
,file_key
,&file_source
);
2751 if (rc
!= ERROR_SUCCESS
)
2753 ERR("Original file unknown %s\n",debugstr_w(file_key
));
2754 msiobj_release(&row
->hdr
);
2755 HeapFree(GetProcessHeap(),0,file_source
);
2759 if (MSI_RecordIsNull(row
,4))
2761 strcpyW(dest_name
,strrchrW(file_source
,'\\')+1);
2766 MSI_RecordGetStringW(row
,4,dest_name
,&sz
);
2767 reduce_to_longfilename(dest_name
);
2770 if (MSI_RecordIsNull(row
,5))
2773 dest_path
= dupstrW(file_source
);
2774 p
= strrchrW(dest_path
,'\\');
2780 WCHAR destkey
[0x100];
2782 MSI_RecordGetStringW(row
,5,destkey
,&sz
);
2784 dest_path
= resolve_folder(package
, destkey
, FALSE
,FALSE
,NULL
);
2787 ERR("Unable to get destination folder\n");
2788 msiobj_release(&row
->hdr
);
2789 HeapFree(GetProcessHeap(),0,file_source
);
2794 dest
= build_directory_name(2, dest_path
, dest_name
);
2795 HeapFree(GetProcessHeap(), 0, dest_path
);
2797 TRACE("Duplicating file %s to %s\n",debugstr_w(file_source
),
2800 if (strcmpW(file_source
,dest
))
2801 rc
= !CopyFileW(file_source
,dest
,TRUE
);
2805 if (rc
!= ERROR_SUCCESS
)
2806 ERR("Failed to copy file\n");
2808 FIXME("We should track these duplicate files as well\n");
2810 msiobj_release(&row
->hdr
);
2811 HeapFree(GetProcessHeap(),0,dest
);
2812 HeapFree(GetProcessHeap(),0,file_source
);
2814 MSI_ViewClose(view
);
2815 msiobj_release(&view
->hdr
);
2820 /* OK this value is "interpretted" and then formatted based on the
2821 first few characters */
2822 static LPSTR
parse_value(MSIPACKAGE
*package
, WCHAR
*value
, DWORD
*type
,
2826 if (value
[0]=='#' && value
[1]!='#' && value
[1]!='%')
2835 deformat_string(package
, &value
[2], &deformated
);
2837 /* binary value type */
2840 *size
= strlenW(ptr
)/2;
2841 data
= HeapAlloc(GetProcessHeap(),0,*size
);
2853 data
[count
] = (BYTE
)strtol(byte
,NULL
,0);
2856 HeapFree(GetProcessHeap(),0,deformated
);
2858 TRACE("Data %li bytes(%i)\n",*size
,count
);
2863 deformat_string(package
, &value
[1], &deformated
);
2866 *size
= sizeof(DWORD
);
2867 data
= HeapAlloc(GetProcessHeap(),0,*size
);
2868 *(LPDWORD
)data
= atoiW(deformated
);
2869 TRACE("DWORD %i\n",*data
);
2871 HeapFree(GetProcessHeap(),0,deformated
);
2876 static const WCHAR szMulti
[] = {'[','~',']',0};
2885 *type
=REG_EXPAND_SZ
;
2893 if (strstrW(value
,szMulti
))
2894 *type
= REG_MULTI_SZ
;
2896 *size
= deformat_string(package
, ptr
,(LPWSTR
*)&data
);
2901 static UINT
ACTION_WriteRegistryValues(MSIPACKAGE
*package
)
2905 MSIRECORD
* row
= 0;
2906 static const WCHAR ExecSeqQuery
[] = {
2907 's','e','l','e','c','t',' ','*',' ',
2908 'f','r','o','m',' ','R','e','g','i','s','t','r','y',0 };
2911 return ERROR_INVALID_HANDLE
;
2913 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
2914 if (rc
!= ERROR_SUCCESS
)
2915 return ERROR_SUCCESS
;
2917 rc
= MSI_ViewExecute(view
, 0);
2918 if (rc
!= ERROR_SUCCESS
)
2920 MSI_ViewClose(view
);
2921 msiobj_release(&view
->hdr
);
2925 /* increment progress bar each time action data is sent */
2926 ui_progress(package
,1,REG_PROGRESS_VALUE
,1,0);
2930 static const WCHAR szHCR
[] =
2931 {'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T','\\',0};
2932 static const WCHAR szHCU
[] =
2933 {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',0};
2934 static const WCHAR szHLM
[] =
2935 {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',
2937 static const WCHAR szHU
[] =
2938 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2940 LPSTR value_data
= NULL
;
2941 HKEY root_key
, hkey
;
2943 LPWSTR value
, key
, name
, component
, deformated
;
2945 INT component_index
;
2950 rc
= MSI_ViewFetch(view
,&row
);
2951 if (rc
!= ERROR_SUCCESS
)
2956 ui_progress(package
,2,0,0,0);
2963 component
= load_dynamic_stringW(row
, 6);
2964 component_index
= get_loaded_component(package
,component
);
2966 if (package
->components
[component_index
].ActionRequest
!=
2969 TRACE("Skipping write due to disabled component\n");
2970 msiobj_release(&row
->hdr
);
2974 /* null values have special meanings during uninstalls and such */
2976 if(MSI_RecordIsNull(row
,5))
2978 msiobj_release(&row
->hdr
);
2982 root
= MSI_RecordGetInteger(row
,2);
2983 key
= load_dynamic_stringW(row
, 3);
2985 name
= load_dynamic_stringW(row
, 4);
2987 /* get the root key */
2990 case 0: root_key
= HKEY_CLASSES_ROOT
;
2993 case 1: root_key
= HKEY_CURRENT_USER
;
2996 case 2: root_key
= HKEY_LOCAL_MACHINE
;
2999 case 3: root_key
= HKEY_USERS
;
3003 ERR("Unknown root %i\n",root
);
3010 msiobj_release(&row
->hdr
);
3014 deformat_string(package
, key
, &deformated
);
3015 size
= strlenW(deformated
) + strlenW(szRoot
) + 1;
3016 uikey
= HeapAlloc(GetProcessHeap(), 0, size
*sizeof(WCHAR
));
3017 strcpyW(uikey
,szRoot
);
3018 strcatW(uikey
,deformated
);
3020 if (RegCreateKeyW( root_key
, deformated
, &hkey
))
3022 ERR("Could not create key %s\n",debugstr_w(deformated
));
3023 msiobj_release(&row
->hdr
);
3024 HeapFree(GetProcessHeap(),0,deformated
);
3027 HeapFree(GetProcessHeap(),0,deformated
);
3029 value
= load_dynamic_stringW(row
,5);
3030 value_data
= parse_value(package
, value
, &type
, &size
);
3032 deformat_string(package
, name
, &deformated
);
3036 TRACE("Setting value %s\n",debugstr_w(deformated
));
3037 RegSetValueExW(hkey
, deformated
, 0, type
, value_data
, size
);
3039 uirow
= MSI_CreateRecord(3);
3040 MSI_RecordSetStringW(uirow
,2,deformated
);
3041 MSI_RecordSetStringW(uirow
,1,uikey
);
3044 MSI_RecordSetStringW(uirow
,3,(LPWSTR
)value_data
);
3046 MSI_RecordSetStringW(uirow
,3,value
);
3048 ui_actiondata(package
,szWriteRegistryValues
,uirow
);
3049 msiobj_release( &uirow
->hdr
);
3051 HeapFree(GetProcessHeap(),0,value_data
);
3053 HeapFree(GetProcessHeap(),0,value
);
3054 HeapFree(GetProcessHeap(),0,deformated
);
3056 msiobj_release(&row
->hdr
);
3059 HeapFree(GetProcessHeap(),0,uikey
);
3060 HeapFree(GetProcessHeap(),0,key
);
3061 HeapFree(GetProcessHeap(),0,name
);
3062 HeapFree(GetProcessHeap(),0,component
);
3064 MSI_ViewClose(view
);
3065 msiobj_release(&view
->hdr
);
3069 static UINT
ACTION_InstallInitialize(MSIPACKAGE
*package
)
3071 return ERROR_SUCCESS
;
3075 static UINT
ACTION_InstallValidate(MSIPACKAGE
*package
)
3079 static const WCHAR q1
[]={
3080 'S','E','L','E','C','T',' ','*',' ',
3081 'F','R','O','M',' ','R','e','g','i','s','t','r','y',0};
3084 MSIRECORD
* row
= 0;
3087 TRACE(" InstallValidate \n");
3089 rc
= MSI_DatabaseOpenViewW(package
->db
, q1
, &view
);
3090 if (rc
!= ERROR_SUCCESS
)
3091 return ERROR_SUCCESS
;
3093 rc
= MSI_ViewExecute(view
, 0);
3094 if (rc
!= ERROR_SUCCESS
)
3096 MSI_ViewClose(view
);
3097 msiobj_release(&view
->hdr
);
3102 rc
= MSI_ViewFetch(view
,&row
);
3103 if (rc
!= ERROR_SUCCESS
)
3110 msiobj_release(&row
->hdr
);
3112 MSI_ViewClose(view
);
3113 msiobj_release(&view
->hdr
);
3115 total
= total
+ progress
* REG_PROGRESS_VALUE
;
3116 total
= total
+ package
->loaded_components
* COMPONENT_PROGRESS_VALUE
;
3117 for (i
=0; i
< package
->loaded_files
; i
++)
3118 total
+= package
->files
[i
].FileSize
;
3119 ui_progress(package
,0,total
,0,0);
3121 return ERROR_SUCCESS
;
3124 static UINT
ACTION_LaunchConditions(MSIPACKAGE
*package
)
3127 MSIQUERY
* view
= NULL
;
3128 MSIRECORD
* row
= 0;
3129 static const WCHAR ExecSeqQuery
[] = {
3130 'S','E','L','E','C','T',' ','*',' ',
3131 'f','r','o','m',' ','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n',0};
3132 static const WCHAR title
[]=
3133 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3135 TRACE("Checking launch conditions\n");
3137 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3138 if (rc
!= ERROR_SUCCESS
)
3139 return ERROR_SUCCESS
;
3141 rc
= MSI_ViewExecute(view
, 0);
3142 if (rc
!= ERROR_SUCCESS
)
3144 MSI_ViewClose(view
);
3145 msiobj_release(&view
->hdr
);
3150 while (rc
== ERROR_SUCCESS
)
3153 LPWSTR message
= NULL
;
3155 rc
= MSI_ViewFetch(view
,&row
);
3156 if (rc
!= ERROR_SUCCESS
)
3162 cond
= load_dynamic_stringW(row
,1);
3164 if (MSI_EvaluateConditionW(package
,cond
) != MSICONDITION_TRUE
)
3167 message
= load_dynamic_stringW(row
,2);
3168 deformat_string(package
,message
,&deformated
);
3169 MessageBoxW(NULL
,deformated
,title
,MB_OK
);
3170 HeapFree(GetProcessHeap(),0,message
);
3171 HeapFree(GetProcessHeap(),0,deformated
);
3172 rc
= ERROR_FUNCTION_FAILED
;
3174 HeapFree(GetProcessHeap(),0,cond
);
3175 msiobj_release(&row
->hdr
);
3177 MSI_ViewClose(view
);
3178 msiobj_release(&view
->hdr
);
3182 static LPWSTR
resolve_keypath( MSIPACKAGE
* package
, INT
3185 MSICOMPONENT
* cmp
= &package
->components
[component_index
];
3187 if (cmp
->KeyPath
[0]==0)
3189 LPWSTR p
= resolve_folder(package
,cmp
->Directory
,FALSE
,FALSE
,NULL
);
3192 if (cmp
->Attributes
& 0x4)
3195 MSIRECORD
* row
= 0;
3197 LPWSTR key
,deformated
,buffer
,name
,deformated_name
;
3198 static const WCHAR ExecSeqQuery
[] = {
3199 's','e','l','e','c','t',' ','*',' ',
3200 'f','r','o','m',' ','R','e','g','i','s','t','r','y',' ',
3201 'w','h','e','r','e',' ','R','e','g','i','s','t','r','y',' ','=',' '
3202 ,'`','%','s','`',0 };
3203 static const WCHAR fmt
[]={'%','0','2','i',':','%','s',0};
3204 static const WCHAR fmt2
[]={'%','0','2','i',':','%','s','\\','%','s',0};
3206 rc
= MSI_OpenQuery(package
->db
,&view
,ExecSeqQuery
,cmp
->KeyPath
);
3208 if (rc
!=ERROR_SUCCESS
)
3211 rc
= MSI_ViewExecute(view
, 0);
3212 if (rc
!= ERROR_SUCCESS
)
3214 MSI_ViewClose(view
);
3215 msiobj_release(&view
->hdr
);
3219 rc
= MSI_ViewFetch(view
,&row
);
3220 if (rc
!= ERROR_SUCCESS
)
3222 MSI_ViewClose(view
);
3223 msiobj_release(&view
->hdr
);
3227 root
= MSI_RecordGetInteger(row
,2);
3228 key
= load_dynamic_stringW(row
, 3);
3229 name
= load_dynamic_stringW(row
, 4);
3230 deformat_string(package
, key
, &deformated
);
3231 deformat_string(package
, name
, &deformated_name
);
3233 len
= strlenW(deformated
) + 5;
3234 if (deformated_name
)
3235 len
+=strlenW(deformated_name
);
3237 buffer
= HeapAlloc(GetProcessHeap(),0, len
*sizeof(WCHAR
));
3239 if (deformated_name
)
3240 sprintfW(buffer
,fmt2
,root
,deformated
,deformated_name
);
3242 sprintfW(buffer
,fmt
,root
,deformated
);
3244 HeapFree(GetProcessHeap(),0,key
);
3245 HeapFree(GetProcessHeap(),0,deformated
);
3246 HeapFree(GetProcessHeap(),0,name
);
3247 HeapFree(GetProcessHeap(),0,deformated_name
);
3248 msiobj_release(&row
->hdr
);
3249 MSI_ViewClose(view
);
3250 msiobj_release(&view
->hdr
);
3254 else if (cmp
->Attributes
& 0x20)
3256 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3262 j
= get_loaded_file(package
,cmp
->KeyPath
);
3266 LPWSTR p
= dupstrW(package
->files
[j
].TargetPath
);
3274 * Ok further analysis makes me think that this work is
3275 * actually done in the PublishComponents and PublishFeatures
3276 * step, and not here. It appears like the keypath and all that is
3277 * resolved in this step, however actually written in the Publish steps.
3278 * But we will leave it here for now because it is unclear
3280 static UINT
ACTION_ProcessComponents(MSIPACKAGE
*package
)
3283 WCHAR squished_pc
[GUID_SIZE
];
3284 WCHAR squished_cc
[GUID_SIZE
];
3287 HKEY hkey
=0,hkey2
=0;
3288 static const WCHAR szProductCode
[]=
3289 {'P','r','o','d','u','c','t','C','o','d','e',0};
3292 return ERROR_INVALID_HANDLE
;
3294 /* writes the Component and Features values to the registry */
3295 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
3299 rc
= MSIREG_OpenComponents(&hkey
);
3300 if (rc
!= ERROR_SUCCESS
)
3303 squash_guid(productcode
,squished_pc
);
3304 ui_progress(package
,1,COMPONENT_PROGRESS_VALUE
,1,0);
3305 for (i
= 0; i
< package
->loaded_components
; i
++)
3307 ui_progress(package
,2,0,0,0);
3308 if (package
->components
[i
].ComponentId
[0]!=0)
3310 WCHAR
*keypath
= NULL
;
3313 squash_guid(package
->components
[i
].ComponentId
,squished_cc
);
3314 rc
= RegCreateKeyW(hkey
,squished_cc
,&hkey2
);
3315 if (rc
!= ERROR_SUCCESS
)
3318 keypath
= resolve_keypath(package
,i
);
3321 RegSetValueExW(hkey2
,squished_pc
,0,REG_SZ
,(LPVOID
)keypath
,
3322 (strlenW(keypath
)+1)*sizeof(WCHAR
));
3326 uirow
= MSI_CreateRecord(3);
3327 MSI_RecordSetStringW(uirow
,1,productcode
);
3328 MSI_RecordSetStringW(uirow
,2,package
->components
[i
].
3330 MSI_RecordSetStringW(uirow
,3,keypath
);
3331 ui_actiondata(package
,szProcessComponents
,uirow
);
3332 msiobj_release( &uirow
->hdr
);
3333 HeapFree(GetProcessHeap(),0,keypath
);
3338 HeapFree(GetProcessHeap(), 0, productcode
);
3343 static UINT
ACTION_RegisterTypeLibraries(MSIPACKAGE
*package
)
3346 * OK this is a bit confusing.. I am given a _Component key and I believe
3347 * that the file that is being registered as a type library is the "key file
3348 * of that component" which I interpret to mean "The file in the KeyPath of
3353 MSIRECORD
* row
= 0;
3354 static const WCHAR Query
[] = {
3355 'S','E','L','E','C','T',' ','*',' ',
3356 'f','r','o','m',' ','T','y','p','e','L','i','b',0};
3361 return ERROR_INVALID_HANDLE
;
3363 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3364 if (rc
!= ERROR_SUCCESS
)
3365 return ERROR_SUCCESS
;
3367 rc
= MSI_ViewExecute(view
, 0);
3368 if (rc
!= ERROR_SUCCESS
)
3370 MSI_ViewClose(view
);
3371 msiobj_release(&view
->hdr
);
3377 WCHAR component
[0x100];
3381 rc
= MSI_ViewFetch(view
,&row
);
3382 if (rc
!= ERROR_SUCCESS
)
3389 MSI_RecordGetStringW(row
,3,component
,&sz
);
3391 index
= get_loaded_component(package
,component
);
3394 msiobj_release(&row
->hdr
);
3398 if (package
->components
[index
].ActionRequest
!= INSTALLSTATE_LOCAL
)
3400 TRACE("Skipping typelib reg due to disabled component\n");
3401 msiobj_release(&row
->hdr
);
3405 index
= get_loaded_file(package
,package
->components
[index
].KeyPath
);
3409 msiobj_release(&row
->hdr
);
3413 res
= LoadTypeLib(package
->files
[index
].TargetPath
,&ptLib
);
3417 WCHAR helpid
[0x100];
3420 MSI_RecordGetStringW(row
,6,helpid
,&sz
);
3422 help
= resolve_folder(package
,helpid
,FALSE
,FALSE
,NULL
);
3423 res
= RegisterTypeLib(ptLib
,package
->files
[index
].TargetPath
,help
);
3424 HeapFree(GetProcessHeap(),0,help
);
3426 if (!SUCCEEDED(res
))
3427 ERR("Failed to register type library %s\n",
3428 debugstr_w(package
->files
[index
].TargetPath
));
3431 /* Yes the row has more fields than I need, but #1 is
3432 correct and the only one I need. Why make a new row? */
3434 ui_actiondata(package
,szRegisterTypeLibraries
,row
);
3436 TRACE("Registered %s\n",
3437 debugstr_w(package
->files
[index
].TargetPath
));
3441 ITypeLib_Release(ptLib
);
3444 ERR("Failed to load type library %s\n",
3445 debugstr_w(package
->files
[index
].TargetPath
));
3447 msiobj_release(&row
->hdr
);
3449 MSI_ViewClose(view
);
3450 msiobj_release(&view
->hdr
);
3455 static UINT
register_appid(MSIPACKAGE
*package
, LPCWSTR clsid
, LPCWSTR app
)
3457 static const WCHAR szAppID
[] = { 'A','p','p','I','D',0 };
3460 MSIRECORD
* row
= 0;
3461 static const WCHAR ExecSeqQuery
[] =
3462 {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'
3463 ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};
3468 return ERROR_INVALID_HANDLE
;
3470 rc
= MSI_OpenQuery(package
->db
, &view
, ExecSeqQuery
, clsid
);
3471 if (rc
!= ERROR_SUCCESS
)
3474 rc
= MSI_ViewExecute(view
, 0);
3475 if (rc
!= ERROR_SUCCESS
)
3477 MSI_ViewClose(view
);
3478 msiobj_release(&view
->hdr
);
3482 RegCreateKeyW(HKEY_CLASSES_ROOT
,szAppID
,&hkey2
);
3483 RegCreateKeyW(hkey2
,clsid
,&hkey3
);
3484 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,(LPVOID
)app
,
3485 (strlenW(app
)+1)*sizeof(WCHAR
));
3487 rc
= MSI_ViewFetch(view
,&row
);
3488 if (rc
!= ERROR_SUCCESS
)
3490 MSI_ViewClose(view
);
3491 msiobj_release(&view
->hdr
);
3495 if (!MSI_RecordIsNull(row
,2))
3497 LPWSTR deformated
=0;
3499 static const WCHAR szRemoteServerName
[] =
3500 {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};
3501 buffer
= load_dynamic_stringW(row
,2);
3502 size
= deformat_string(package
,buffer
,&deformated
);
3503 RegSetValueExW(hkey3
,szRemoteServerName
,0,REG_SZ
,(LPVOID
)deformated
,
3505 HeapFree(GetProcessHeap(),0,deformated
);
3506 HeapFree(GetProcessHeap(),0,buffer
);
3509 if (!MSI_RecordIsNull(row
,3))
3511 static const WCHAR szLocalService
[] =
3512 {'L','o','c','a','l','S','e','r','v','i','c','e',0};
3514 buffer
= load_dynamic_stringW(row
,3);
3515 size
= (strlenW(buffer
)+1) * sizeof(WCHAR
);
3516 RegSetValueExW(hkey3
,szLocalService
,0,REG_SZ
,(LPVOID
)buffer
,size
);
3517 HeapFree(GetProcessHeap(),0,buffer
);
3520 if (!MSI_RecordIsNull(row
,4))
3522 static const WCHAR szService
[] =
3523 {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};
3525 buffer
= load_dynamic_stringW(row
,4);
3526 size
= (strlenW(buffer
)+1) * sizeof(WCHAR
);
3527 RegSetValueExW(hkey3
,szService
,0,REG_SZ
,(LPVOID
)buffer
,size
);
3528 HeapFree(GetProcessHeap(),0,buffer
);
3531 if (!MSI_RecordIsNull(row
,5))
3533 static const WCHAR szDLL
[] =
3534 {'D','l','l','S','u','r','r','o','g','a','t','e',0};
3536 buffer
= load_dynamic_stringW(row
,5);
3537 size
= (strlenW(buffer
)+1) * sizeof(WCHAR
);
3538 RegSetValueExW(hkey3
,szDLL
,0,REG_SZ
,(LPVOID
)buffer
,size
);
3539 HeapFree(GetProcessHeap(),0,buffer
);
3542 if (!MSI_RecordIsNull(row
,6))
3544 static const WCHAR szActivate
[] =
3545 {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};
3546 static const WCHAR szY
[] = {'Y',0};
3548 if (MSI_RecordGetInteger(row
,6))
3549 RegSetValueExW(hkey3
,szActivate
,0,REG_SZ
,(LPVOID
)szY
,4);
3552 if (!MSI_RecordIsNull(row
,7))
3554 static const WCHAR szRunAs
[] = {'R','u','n','A','s',0};
3555 static const WCHAR szUser
[] =
3556 {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};
3558 if (MSI_RecordGetInteger(row
,7))
3559 RegSetValueExW(hkey3
,szRunAs
,0,REG_SZ
,(LPVOID
)szUser
,34);
3562 msiobj_release(&row
->hdr
);
3563 MSI_ViewClose(view
);
3564 msiobj_release(&view
->hdr
);
3570 static UINT
ACTION_RegisterClassInfo(MSIPACKAGE
*package
)
3573 * Again I am assuming the words, "Whose key file represents" when referring
3574 * to a Component as to meaning that Components KeyPath file
3576 * Also there is a very strong connection between ClassInfo and ProgID
3577 * that I am mostly glossing over.
3578 * What would be more propper is to load the ClassInfo and the ProgID info
3579 * into memory data structures and then be able to enable and disable them
3580 * based on component.
3585 MSIRECORD
* row
= 0;
3586 static const WCHAR ExecSeqQuery
[] = {
3587 'S','E','L','E','C','T',' ','*',' ',
3588 'f','r','o','m',' ','C','l','a','s','s',0};
3589 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
3590 static const WCHAR szProgID
[] = { 'P','r','o','g','I','D',0 };
3591 static const WCHAR szAppID
[] = { 'A','p','p','I','D',0 };
3592 HKEY hkey
,hkey2
,hkey3
;
3595 return ERROR_INVALID_HANDLE
;
3597 rc
= RegCreateKeyW(HKEY_CLASSES_ROOT
,szCLSID
,&hkey
);
3598 if (rc
!= ERROR_SUCCESS
)
3599 return ERROR_FUNCTION_FAILED
;
3601 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
3602 if (rc
!= ERROR_SUCCESS
)
3608 rc
= MSI_ViewExecute(view
, 0);
3609 if (rc
!= ERROR_SUCCESS
)
3611 MSI_ViewClose(view
);
3612 msiobj_release(&view
->hdr
);
3619 WCHAR buffer
[0x100];
3624 rc
= MSI_ViewFetch(view
,&row
);
3625 if (rc
!= ERROR_SUCCESS
)
3632 MSI_RecordGetStringW(row
,3,buffer
,&sz
);
3634 index
= get_loaded_component(package
,buffer
);
3638 msiobj_release(&row
->hdr
);
3642 if (package
->components
[index
].ActionRequest
!= INSTALLSTATE_LOCAL
)
3644 TRACE("Skipping class reg due to disabled component\n");
3645 msiobj_release(&row
->hdr
);
3650 MSI_RecordGetStringW(row
,1,clsid
,&sz
);
3651 RegCreateKeyW(hkey
,clsid
,&hkey2
);
3653 if (!MSI_RecordIsNull(row
,5))
3656 MSI_RecordGetStringW(row
,5,desc
,&sz
);
3658 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)desc
,
3659 (strlenW(desc
)+1)*sizeof(WCHAR
));
3665 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
3667 RegCreateKeyW(hkey2
,buffer
,&hkey3
);
3669 index
= get_loaded_file(package
,package
->components
[index
].KeyPath
);
3670 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,
3671 (LPVOID
)package
->files
[index
].TargetPath
,
3672 (strlenW(package
->files
[index
].TargetPath
)+1)
3677 if (!MSI_RecordIsNull(row
,4))
3680 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
3682 RegCreateKeyW(hkey2
,szProgID
,&hkey3
);
3684 RegSetValueExW(hkey3
,NULL
,0,REG_SZ
,(LPVOID
)buffer
,
3685 (strlenW(buffer
)+1)*sizeof(WCHAR
));
3690 if (!MSI_RecordIsNull(row
,6))
3693 MSI_RecordGetStringW(row
,6,buffer
,&sz
);
3695 RegSetValueExW(hkey2
,szAppID
,0,REG_SZ
,(LPVOID
)buffer
,
3696 (strlenW(buffer
)+1)*sizeof(WCHAR
));
3698 register_appid(package
,buffer
,desc
);
3703 FIXME("Process the rest of the fields >7\n");
3705 ui_actiondata(package
,szRegisterClassInfo
,row
);
3707 msiobj_release(&row
->hdr
);
3709 MSI_ViewClose(view
);
3710 msiobj_release(&view
->hdr
);
3717 static UINT
register_progid_base(MSIPACKAGE
* package
, MSIRECORD
* row
,
3720 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
3721 static const WCHAR szDefaultIcon
[] = {
3722 'D','e','f','a','u','l','t','I','c','o','n',0};
3724 WCHAR buffer
[0x100];
3729 MSI_RecordGetStringW(row
,1,buffer
,&sz
);
3730 RegCreateKeyW(HKEY_CLASSES_ROOT
,buffer
,&hkey
);
3732 if (!MSI_RecordIsNull(row
,4))
3735 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
3736 RegSetValueExW(hkey
,NULL
,0,REG_SZ
,(LPVOID
)buffer
, (strlenW(buffer
)+1) *
3740 if (!MSI_RecordIsNull(row
,3))
3744 MSI_RecordGetStringW(row
,3,buffer
,&sz
);
3745 RegCreateKeyW(hkey
,szCLSID
,&hkey2
);
3746 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)buffer
, (strlenW(buffer
)+1) *
3750 strcpyW(clsid
,buffer
);
3756 FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
3757 return ERROR_FUNCTION_FAILED
;
3759 if (!MSI_RecordIsNull(row
,5))
3761 INT index
= MSI_RecordGetInteger(row
,6);
3762 LPWSTR FileName
= load_dynamic_stringW(row
,5);
3763 LPWSTR FilePath
,IconPath
;
3764 static const WCHAR fmt
[] = {'%','s',',','%','i',0};
3766 RegCreateKeyW(hkey
,szDefaultIcon
,&hkey2
);
3767 build_icon_path(package
,FileName
,&FilePath
);
3769 IconPath
= HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath
)+5)*
3772 sprintfW(IconPath
,fmt
,FilePath
,index
);
3773 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)IconPath
,
3774 (strlenW(IconPath
)+1) * sizeof(WCHAR
));
3775 HeapFree(GetProcessHeap(),0,FilePath
);
3776 HeapFree(GetProcessHeap(),0,FileName
);
3779 return ERROR_SUCCESS
;
3782 static UINT
register_progid(MSIPACKAGE
*package
, MSIRECORD
* row
, LPWSTR clsid
);
3784 static UINT
register_parent_progid(MSIPACKAGE
*package
, LPCWSTR parent
,
3789 MSIRECORD
* row
= 0;
3790 static const WCHAR Query_t
[] =
3791 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'
3792 ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'
3796 return ERROR_INVALID_HANDLE
;
3798 rc
= MSI_OpenQuery(package
->db
, &view
, Query_t
, parent
);
3799 if (rc
!= ERROR_SUCCESS
)
3802 rc
= MSI_ViewExecute(view
, 0);
3803 if (rc
!= ERROR_SUCCESS
)
3805 MSI_ViewClose(view
);
3806 msiobj_release(&view
->hdr
);
3810 rc
= MSI_ViewFetch(view
,&row
);
3811 if (rc
!= ERROR_SUCCESS
)
3813 MSI_ViewClose(view
);
3814 msiobj_release(&view
->hdr
);
3818 register_progid(package
,row
,clsid
);
3820 msiobj_release(&row
->hdr
);
3821 MSI_ViewClose(view
);
3822 msiobj_release(&view
->hdr
);
3826 static UINT
register_progid(MSIPACKAGE
*package
, MSIRECORD
* row
, LPWSTR clsid
)
3828 UINT rc
= ERROR_SUCCESS
;
3830 if (MSI_RecordIsNull(row
,2))
3831 rc
= register_progid_base(package
,row
,clsid
);
3834 WCHAR buffer
[0x1000];
3837 static const WCHAR szCLSID
[] = { 'C','L','S','I','D',0 };
3838 static const WCHAR szDefaultIcon
[] = {
3839 'D','e','f','a','u','l','t','I','c','o','n',0};
3841 /* check if already registered */
3843 MSI_RecordGetStringW(row
,1,buffer
,&sz
);
3844 RegCreateKeyExW(HKEY_CLASSES_ROOT
, buffer
, 0, NULL
, 0,
3845 KEY_ALL_ACCESS
, NULL
, &hkey
, &disp
);
3846 if (disp
== REG_OPENED_EXISTING_KEY
)
3848 TRACE("Key already registered\n");
3854 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
3855 rc
= register_parent_progid(package
,buffer
,clsid
);
3857 /* clsid is same as parent */
3858 RegCreateKeyW(hkey
,szCLSID
,&hkey2
);
3859 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)clsid
, (strlenW(clsid
)+1) *
3865 if (!MSI_RecordIsNull(row
,4))
3868 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
3869 RegSetValueExW(hkey
,NULL
,0,REG_SZ
,(LPVOID
)buffer
,
3870 (strlenW(buffer
)+1) * sizeof(WCHAR
));
3873 if (!MSI_RecordIsNull(row
,5))
3875 LPWSTR FileName
= load_dynamic_stringW(row
,5);
3877 RegCreateKeyW(hkey
,szDefaultIcon
,&hkey2
);
3878 build_icon_path(package
,FileName
,&FilePath
);
3879 RegSetValueExW(hkey2
,NULL
,0,REG_SZ
,(LPVOID
)FilePath
,
3880 (strlenW(FilePath
)+1) * sizeof(WCHAR
));
3881 HeapFree(GetProcessHeap(),0,FilePath
);
3882 HeapFree(GetProcessHeap(),0,FileName
);
3891 static UINT
ACTION_RegisterProgIdInfo(MSIPACKAGE
*package
)
3894 * Sigh, here I am just brute force registering all progids
3895 * this needs to be linked to the Classes that have been registered
3896 * but the easiest way to do that is to load all these stuff into
3897 * memory for easy checking.
3899 * Gives me something to continue to work toward.
3903 MSIRECORD
* row
= 0;
3904 static const WCHAR Query
[] = {
3905 'S','E','L','E','C','T',' ','*',' ',
3906 'F','R','O','M',' ','P','r','o','g','I','d',0};
3909 return ERROR_INVALID_HANDLE
;
3911 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
3912 if (rc
!= ERROR_SUCCESS
)
3913 return ERROR_SUCCESS
;
3915 rc
= MSI_ViewExecute(view
, 0);
3916 if (rc
!= ERROR_SUCCESS
)
3918 MSI_ViewClose(view
);
3919 msiobj_release(&view
->hdr
);
3925 WCHAR clsid
[0x1000];
3927 rc
= MSI_ViewFetch(view
,&row
);
3928 if (rc
!= ERROR_SUCCESS
)
3934 register_progid(package
,row
,clsid
);
3935 ui_actiondata(package
,szRegisterProgIdInfo
,row
);
3937 msiobj_release(&row
->hdr
);
3939 MSI_ViewClose(view
);
3940 msiobj_release(&view
->hdr
);
3944 static UINT
build_icon_path(MSIPACKAGE
*package
, LPCWSTR icon_name
,
3948 LPWSTR SystemFolder
;
3952 static const WCHAR szInstaller
[] =
3953 {'I','n','s','t','a','l','l','e','r','\\',0};
3954 static const WCHAR szProductCode
[] =
3955 {'P','r','o','d','u','c','t','C','o','d','e',0};
3956 static const WCHAR szFolder
[] =
3957 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3959 ProductCode
= load_dynamic_property(package
,szProductCode
,&rc
);
3963 SystemFolder
= load_dynamic_property(package
,szFolder
,NULL
);
3965 dest
= build_directory_name(3, SystemFolder
, szInstaller
, ProductCode
);
3967 create_full_pathW(dest
);
3969 *FilePath
= build_directory_name(2, dest
, icon_name
);
3971 HeapFree(GetProcessHeap(),0,SystemFolder
);
3972 HeapFree(GetProcessHeap(),0,ProductCode
);
3973 HeapFree(GetProcessHeap(),0,dest
);
3974 return ERROR_SUCCESS
;
3977 static UINT
ACTION_CreateShortcuts(MSIPACKAGE
*package
)
3981 MSIRECORD
* row
= 0;
3982 static const WCHAR Query
[] = {
3983 'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ',
3984 'S','h','o','r','t','c','u','t',0};
3990 return ERROR_INVALID_HANDLE
;
3992 res
= CoInitialize( NULL
);
3995 ERR("CoInitialize failed\n");
3996 return ERROR_FUNCTION_FAILED
;
3999 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
4000 if (rc
!= ERROR_SUCCESS
)
4001 return ERROR_SUCCESS
;
4003 rc
= MSI_ViewExecute(view
, 0);
4004 if (rc
!= ERROR_SUCCESS
)
4006 MSI_ViewClose(view
);
4007 msiobj_release(&view
->hdr
);
4013 LPWSTR target_file
, target_folder
;
4014 WCHAR buffer
[0x100];
4017 static const WCHAR szlnk
[]={'.','l','n','k',0};
4019 rc
= MSI_ViewFetch(view
,&row
);
4020 if (rc
!= ERROR_SUCCESS
)
4027 MSI_RecordGetStringW(row
,4,buffer
,&sz
);
4029 index
= get_loaded_component(package
,buffer
);
4033 msiobj_release(&row
->hdr
);
4037 if (package
->components
[index
].ActionRequest
!= INSTALLSTATE_LOCAL
)
4039 TRACE("Skipping shortcut creation due to disabled component\n");
4040 msiobj_release(&row
->hdr
);
4044 ui_actiondata(package
,szCreateShortcuts
,row
);
4046 res
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
4047 &IID_IShellLinkW
, (LPVOID
*) &sl
);
4051 ERR("Is IID_IShellLink\n");
4052 msiobj_release(&row
->hdr
);
4056 res
= IShellLinkW_QueryInterface( sl
, &IID_IPersistFile
,(LPVOID
*) &pf
);
4059 ERR("Is IID_IPersistFile\n");
4060 msiobj_release(&row
->hdr
);
4065 MSI_RecordGetStringW(row
,2,buffer
,&sz
);
4066 target_folder
= resolve_folder(package
, buffer
,FALSE
,FALSE
,NULL
);
4068 /* may be needed because of a bug somehwere else */
4069 create_full_pathW(target_folder
);
4072 MSI_RecordGetStringW(row
,3,buffer
,&sz
);
4073 reduce_to_longfilename(buffer
);
4074 if (!strchrW(buffer
,'.') || strcmpiW(strchrW(buffer
,'.'),szlnk
))
4075 strcatW(buffer
,szlnk
);
4076 target_file
= build_directory_name(2, target_folder
, buffer
);
4077 HeapFree(GetProcessHeap(),0,target_folder
);
4080 MSI_RecordGetStringW(row
,5,buffer
,&sz
);
4081 if (strchrW(buffer
,'['))
4084 deformat_string(package
,buffer
,&deformated
);
4085 IShellLinkW_SetPath(sl
,deformated
);
4086 HeapFree(GetProcessHeap(),0,deformated
);
4090 FIXME("UNHANDLED shortcut format, advertised shortcut\n");
4091 IPersistFile_Release( pf
);
4092 IShellLinkW_Release( sl
);
4093 msiobj_release(&row
->hdr
);
4097 if (!MSI_RecordIsNull(row
,6))
4101 MSI_RecordGetStringW(row
,6,buffer
,&sz
);
4102 deformat_string(package
,buffer
,&deformated
);
4103 IShellLinkW_SetArguments(sl
,deformated
);
4104 HeapFree(GetProcessHeap(),0,deformated
);
4107 if (!MSI_RecordIsNull(row
,7))
4110 deformated
= load_dynamic_stringW(row
,7);
4111 IShellLinkW_SetDescription(sl
,deformated
);
4112 HeapFree(GetProcessHeap(),0,deformated
);
4115 if (!MSI_RecordIsNull(row
,8))
4116 IShellLinkW_SetHotkey(sl
,MSI_RecordGetInteger(row
,8));
4118 if (!MSI_RecordIsNull(row
,9))
4124 MSI_RecordGetStringW(row
,9,buffer
,&sz
);
4126 build_icon_path(package
,buffer
,&Path
);
4127 index
= MSI_RecordGetInteger(row
,10);
4129 IShellLinkW_SetIconLocation(sl
,Path
,index
);
4130 HeapFree(GetProcessHeap(),0,Path
);
4133 if (!MSI_RecordIsNull(row
,11))
4134 IShellLinkW_SetShowCmd(sl
,MSI_RecordGetInteger(row
,11));
4136 if (!MSI_RecordIsNull(row
,12))
4140 MSI_RecordGetStringW(row
,12,buffer
,&sz
);
4141 Path
= resolve_folder(package
, buffer
, FALSE
, FALSE
, NULL
);
4142 IShellLinkW_SetWorkingDirectory(sl
,Path
);
4143 HeapFree(GetProcessHeap(), 0, Path
);
4146 TRACE("Writing shortcut to %s\n",debugstr_w(target_file
));
4147 IPersistFile_Save(pf
,target_file
,FALSE
);
4149 HeapFree(GetProcessHeap(),0,target_file
);
4151 IPersistFile_Release( pf
);
4152 IShellLinkW_Release( sl
);
4154 msiobj_release(&row
->hdr
);
4156 MSI_ViewClose(view
);
4157 msiobj_release(&view
->hdr
);
4167 * 99% of the work done here is only done for
4168 * advertised installs. However this is where the
4169 * Icon table is processed and written out
4170 * so that is what I am going to do here.
4172 static UINT
ACTION_PublishProduct(MSIPACKAGE
*package
)
4176 MSIRECORD
* row
= 0;
4177 static const WCHAR Query
[]={
4178 'S','E','L','E','C','T',' ','*',' ',
4179 'f','r','o','m',' ','I','c','o','n',0};
4181 /* for registry stuff */
4185 static const WCHAR szProductCode
[]=
4186 {'P','r','o','d','u','c','t','C','o','d','e',0};
4187 static const WCHAR szProductName
[] = {
4188 'P','r','o','d','u','c','t','N','a','m','e',0};
4189 static const WCHAR szPackageCode
[] = {
4190 'P','a','c','k','a','g','e','C','o','d','e',0};
4193 MSIHANDLE hDb
, hSumInfo
;
4196 return ERROR_INVALID_HANDLE
;
4198 rc
= MSI_DatabaseOpenViewW(package
->db
, Query
, &view
);
4199 if (rc
!= ERROR_SUCCESS
)
4202 rc
= MSI_ViewExecute(view
, 0);
4203 if (rc
!= ERROR_SUCCESS
)
4205 MSI_ViewClose(view
);
4206 msiobj_release(&view
->hdr
);
4213 WCHAR
*FilePath
=NULL
;
4214 WCHAR
*FileName
=NULL
;
4217 rc
= MSI_ViewFetch(view
,&row
);
4218 if (rc
!= ERROR_SUCCESS
)
4224 FileName
= load_dynamic_stringW(row
,1);
4227 ERR("Unable to get FileName\n");
4228 msiobj_release(&row
->hdr
);
4232 build_icon_path(package
,FileName
,&FilePath
);
4234 HeapFree(GetProcessHeap(),0,FileName
);
4236 TRACE("Creating icon file at %s\n",debugstr_w(FilePath
));
4238 the_file
= CreateFileW(FilePath
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
4239 FILE_ATTRIBUTE_NORMAL
, NULL
);
4241 if (the_file
== INVALID_HANDLE_VALUE
)
4243 ERR("Unable to create file %s\n",debugstr_w(FilePath
));
4244 msiobj_release(&row
->hdr
);
4245 HeapFree(GetProcessHeap(),0,FilePath
);
4253 rc
= MSI_RecordReadStream(row
,2,buffer
,&sz
);
4254 if (rc
!= ERROR_SUCCESS
)
4256 ERR("Failed to get stream\n");
4257 CloseHandle(the_file
);
4258 DeleteFileW(FilePath
);
4261 WriteFile(the_file
,buffer
,sz
,&write
,NULL
);
4262 } while (sz
== 1024);
4264 HeapFree(GetProcessHeap(),0,FilePath
);
4266 CloseHandle(the_file
);
4267 msiobj_release(&row
->hdr
);
4269 MSI_ViewClose(view
);
4270 msiobj_release(&view
->hdr
);
4273 /* ok there is alot more done here but i need to figure out what */
4274 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
4278 rc
= MSIREG_OpenProductsKey(productcode
,&hkey
,TRUE
);
4279 if (rc
!= ERROR_SUCCESS
)
4282 rc
= MSIREG_OpenUserProductsKey(productcode
,&hukey
,TRUE
);
4283 if (rc
!= ERROR_SUCCESS
)
4287 buffer
= load_dynamic_property(package
,szProductName
,NULL
);
4288 size
= strlenW(buffer
)*sizeof(WCHAR
);
4289 RegSetValueExW(hukey
,szProductName
,0,REG_SZ
, (LPSTR
)buffer
,size
);
4290 HeapFree(GetProcessHeap(),0,buffer
);
4291 FIXME("Need to write more keys to the user registry\n");
4293 hDb
= msiobj_findhandle( &package
->db
->hdr
);
4294 rc
= MsiGetSummaryInformationW(hDb
, NULL
, 0, &hSumInfo
);
4295 if (rc
== ERROR_SUCCESS
)
4297 WCHAR guidbuffer
[0x200];
4299 rc
= MsiSummaryInfoGetPropertyW(hSumInfo
, 8, NULL
, NULL
, NULL
,
4301 if (rc
== ERROR_SUCCESS
)
4303 WCHAR squashed
[GUID_SIZE
];
4304 /* for now we only care about the first guid */
4305 LPWSTR ptr
= strchrW(guidbuffer
,';');
4307 squash_guid(guidbuffer
,squashed
);
4308 size
= strlenW(guidbuffer
)*sizeof(WCHAR
);
4309 RegSetValueExW(hukey
,szPackageCode
,0,REG_SZ
, (LPSTR
)guidbuffer
,
4315 ERR("Unable to query Revision_Number... \n");
4318 MsiCloseHandle(hSumInfo
);
4322 ERR("Unable to open Summary Information\n");
4328 HeapFree(GetProcessHeap(),0,productcode
);
4335 static UINT
ACTION_WriteIniValues(MSIPACKAGE
*package
)
4339 MSIRECORD
* row
= 0;
4340 static const WCHAR ExecSeqQuery
[] = {'S','e','l','e','c','t',' ','*',
4341 ' ','f','r','o','m',' ','I','n','i','F','i','l','e',0};
4342 static const WCHAR szWindowsFolder
[] =
4343 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
4344 static const WCHAR szbs
[] = {'\\',0};
4346 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4347 if (rc
!= ERROR_SUCCESS
)
4349 TRACE("no IniFile table\n");
4350 return ERROR_SUCCESS
;
4353 rc
= MSI_ViewExecute(view
, 0);
4354 if (rc
!= ERROR_SUCCESS
)
4356 MSI_ViewClose(view
);
4357 msiobj_release(&view
->hdr
);
4363 LPWSTR component
,filename
,dirproperty
,section
,key
,value
,identifier
;
4364 LPWSTR deformated_section
, deformated_key
, deformated_value
;
4365 LPWSTR folder
, fullname
= NULL
;
4367 INT component_index
,action
;
4369 rc
= MSI_ViewFetch(view
,&row
);
4370 if (rc
!= ERROR_SUCCESS
)
4376 component
= load_dynamic_stringW(row
, 8);
4377 component_index
= get_loaded_component(package
,component
);
4378 HeapFree(GetProcessHeap(),0,component
);
4380 if (package
->components
[component_index
].ActionRequest
!=
4383 TRACE("Skipping ini file due to disabled component\n");
4384 msiobj_release(&row
->hdr
);
4388 identifier
= load_dynamic_stringW(row
,1);
4389 filename
= load_dynamic_stringW(row
,2);
4390 dirproperty
= load_dynamic_stringW(row
,3);
4391 section
= load_dynamic_stringW(row
,4);
4392 key
= load_dynamic_stringW(row
,5);
4393 value
= load_dynamic_stringW(row
,6);
4394 action
= MSI_RecordGetInteger(row
,7);
4396 deformat_string(package
,section
,&deformated_section
);
4397 deformat_string(package
,key
,&deformated_key
);
4398 deformat_string(package
,value
,&deformated_value
);
4402 folder
= resolve_folder(package
, dirproperty
, FALSE
, FALSE
, NULL
);
4404 folder
= load_dynamic_property(package
,dirproperty
,NULL
);
4407 folder
= load_dynamic_property(package
, szWindowsFolder
, NULL
);
4411 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty
));
4416 fullname
= HeapAlloc(GetProcessHeap(),0,
4417 (strlenW(folder
)+strlenW(filename
)+2)*sizeof(WCHAR
));
4419 strcpyW(fullname
,folder
);
4420 if (fullname
[strlenW(folder
)] != '\\')
4421 strcatW(fullname
,szbs
);
4422 strcatW(fullname
,filename
);
4426 TRACE("Adding value %s to section %s in %s\n",
4427 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
4428 debugstr_w(fullname
));
4429 WritePrivateProfileStringW(deformated_section
, deformated_key
,
4430 deformated_value
, fullname
);
4432 else if (action
== 1)
4435 GetPrivateProfileStringW(deformated_section
, deformated_key
, NULL
,
4436 returned
, 10, fullname
);
4437 if (returned
[0] == 0)
4439 TRACE("Adding value %s to section %s in %s\n",
4440 debugstr_w(deformated_key
), debugstr_w(deformated_section
),
4441 debugstr_w(fullname
));
4443 WritePrivateProfileStringW(deformated_section
, deformated_key
,
4444 deformated_value
, fullname
);
4447 else if (action
== 3)
4449 FIXME("Append to existing section not yet implemented\n");
4452 uirow
= MSI_CreateRecord(4);
4453 MSI_RecordSetStringW(uirow
,1,identifier
);
4454 MSI_RecordSetStringW(uirow
,2,deformated_section
);
4455 MSI_RecordSetStringW(uirow
,3,deformated_key
);
4456 MSI_RecordSetStringW(uirow
,4,deformated_value
);
4457 ui_actiondata(package
,szWriteIniValues
,uirow
);
4458 msiobj_release( &uirow
->hdr
);
4460 HeapFree(GetProcessHeap(),0,identifier
);
4461 HeapFree(GetProcessHeap(),0,fullname
);
4462 HeapFree(GetProcessHeap(),0,filename
);
4463 HeapFree(GetProcessHeap(),0,key
);
4464 HeapFree(GetProcessHeap(),0,value
);
4465 HeapFree(GetProcessHeap(),0,section
);
4466 HeapFree(GetProcessHeap(),0,dirproperty
);
4467 HeapFree(GetProcessHeap(),0,folder
);
4468 HeapFree(GetProcessHeap(),0,deformated_key
);
4469 HeapFree(GetProcessHeap(),0,deformated_value
);
4470 HeapFree(GetProcessHeap(),0,deformated_section
);
4471 msiobj_release(&row
->hdr
);
4473 MSI_ViewClose(view
);
4474 msiobj_release(&view
->hdr
);
4478 static UINT
ACTION_SelfRegModules(MSIPACKAGE
*package
)
4482 MSIRECORD
* row
= 0;
4483 static const WCHAR ExecSeqQuery
[] = {'S','e','l','e','c','t',' ','*',' ',
4484 'f','r','o','m',' ','S','e','l','f','R','e','g',0};
4486 static const WCHAR ExeStr
[] = {
4487 'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','s',' ',0};
4489 PROCESS_INFORMATION info
;
4492 memset(&si
,0,sizeof(STARTUPINFOW
));
4494 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
4495 if (rc
!= ERROR_SUCCESS
)
4497 TRACE("no SelfReg table\n");
4498 return ERROR_SUCCESS
;
4501 rc
= MSI_ViewExecute(view
, 0);
4502 if (rc
!= ERROR_SUCCESS
)
4504 MSI_ViewClose(view
);
4505 msiobj_release(&view
->hdr
);
4515 rc
= MSI_ViewFetch(view
,&row
);
4516 if (rc
!= ERROR_SUCCESS
)
4522 filename
= load_dynamic_stringW(row
,1);
4523 index
= get_loaded_file(package
,filename
);
4527 ERR("Unable to find file id %s\n",debugstr_w(filename
));
4528 HeapFree(GetProcessHeap(),0,filename
);
4529 msiobj_release(&row
->hdr
);
4532 HeapFree(GetProcessHeap(),0,filename
);
4534 len
= strlenW(ExeStr
);
4535 len
+= strlenW(package
->files
[index
].TargetPath
);
4538 filename
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
4539 strcpyW(filename
,ExeStr
);
4540 strcatW(filename
,package
->files
[index
].TargetPath
);
4542 TRACE("Registering %s\n",debugstr_w(filename
));
4543 brc
= CreateProcessW(NULL
, filename
, NULL
, NULL
, FALSE
, 0, NULL
,
4544 c_collen
, &si
, &info
);
4547 WaitForSingleObject(info
.hProcess
,INFINITE
);
4549 HeapFree(GetProcessHeap(),0,filename
);
4550 msiobj_release(&row
->hdr
);
4552 MSI_ViewClose(view
);
4553 msiobj_release(&view
->hdr
);
4557 static UINT
ACTION_PublishFeatures(MSIPACKAGE
*package
)
4564 static const WCHAR szProductCode
[]=
4565 {'P','r','o','d','u','c','t','C','o','d','e',0};
4568 return ERROR_INVALID_HANDLE
;
4570 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
4574 rc
= MSIREG_OpenFeaturesKey(productcode
,&hkey
,TRUE
);
4575 if (rc
!= ERROR_SUCCESS
)
4578 rc
= MSIREG_OpenUserFeaturesKey(productcode
,&hukey
,TRUE
);
4579 if (rc
!= ERROR_SUCCESS
)
4582 /* here the guids are base 85 encoded */
4583 for (i
= 0; i
< package
->loaded_features
; i
++)
4590 size
= package
->features
[i
].ComponentCount
*21;
4592 if (package
->features
[i
].Feature_Parent
[0])
4593 size
+= strlenW(package
->features
[i
].Feature_Parent
)+2;
4595 data
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
4598 for (j
= 0; j
< package
->features
[i
].ComponentCount
; j
++)
4601 memset(buf
,0,sizeof(buf
));
4602 TRACE("From %s\n",debugstr_w(package
->components
4603 [package
->features
[i
].Components
[j
]].ComponentId
));
4604 CLSIDFromString(package
->components
4605 [package
->features
[i
].Components
[j
]].ComponentId
,
4607 encode_base85_guid(&clsid
,buf
);
4608 TRACE("to %s\n",debugstr_w(buf
));
4611 if (package
->features
[i
].Feature_Parent
[0])
4613 static const WCHAR sep
[] = {'\2',0};
4615 strcatW(data
,package
->features
[i
].Feature_Parent
);
4618 size
= (strlenW(data
)+1)*sizeof(WCHAR
);
4619 RegSetValueExW(hkey
,package
->features
[i
].Feature
,0,REG_SZ
,
4621 HeapFree(GetProcessHeap(),0,data
);
4623 size
= strlenW(package
->features
[i
].Feature_Parent
)*sizeof(WCHAR
);
4624 RegSetValueExW(hukey
,package
->features
[i
].Feature
,0,REG_SZ
,
4625 (LPSTR
)package
->features
[i
].Feature_Parent
,size
);
4631 HeapFree(GetProcessHeap(), 0, productcode
);
4635 static UINT
ACTION_RegisterProduct(MSIPACKAGE
*package
)
4637 static const WCHAR szProductCode
[]=
4638 {'P','r','o','d','u','c','t','C','o','d','e',0};
4644 static WCHAR szNONE
[] = {0};
4645 static const WCHAR szWindowsInstaler
[] =
4646 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4647 static const WCHAR szPropKeys
[][80] =
4649 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0},
4650 {'A','R','P','C','O','N','T','A','C','T'},
4651 {'A','R','P','C','O','M','M','E','N','T','S',0},
4652 {'P','r','o','d','u','c','t','N','a','m','e',0},
4653 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0},
4654 {'A','R','P','H','E','L','P','L','I','N','K',0},
4655 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0},
4656 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0},
4657 {'S','O','U','R','C','E','D','I','R',0},
4658 {'M','a','n','u','f','a','c','t','u','r','e','r',0},
4659 {'A','R','P','R','E','A','D','M','E',0},
4660 {'A','R','P','S','I','Z','E',0},
4661 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0},
4662 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0},
4666 static const WCHAR szRegKeys
[][80] =
4668 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0},
4669 {'C','o','n','t','a','c','t',0},
4670 {'C','o','m','m','e','n','t','s',0},
4671 {'D','i','s','p','l','a','y','N','a','m','e',0},
4672 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0},
4673 {'H','e','l','p','L','i','n','k',0},
4674 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0},
4675 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0},
4676 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0},
4677 {'P','u','b','l','i','s','h','e','r',0},
4678 {'R','e','a','d','m','e',0},
4679 {'S','i','z','e',0},
4680 {'U','R','L','I','n','f','o','A','b','o','u','t',0},
4681 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0},
4685 static const WCHAR path
[] = {
4686 'C',':','\\','W','i','n','d','o','w','s','\\',
4687 'I','n','s','t','a','l','l','e','r','\\'};
4688 static const WCHAR fmt
[] = {
4689 'C',':','\\','W','i','n','d','o','w','s','\\',
4690 'I','n','s','t','a','l','l','e','r','\\',
4691 '%','x','.','m','s','i',0};
4692 static const WCHAR szLocalPackage
[]=
4693 {'L','o','c','a','l','P','a','c','k','a','g','e',0};
4694 WCHAR packagefile
[MAX_PATH
];
4698 return ERROR_INVALID_HANDLE
;
4700 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
4704 rc
= MSIREG_OpenUninstallKey(productcode
,&hkey
,TRUE
);
4705 if (rc
!= ERROR_SUCCESS
)
4708 /* dump all the info i can grab */
4709 FIXME("Flesh out more information \n");
4712 while (szPropKeys
[i
][0]!=0)
4714 buffer
= load_dynamic_property(package
,szPropKeys
[i
],&rc
);
4715 if (rc
!= ERROR_SUCCESS
)
4717 size
= strlenW(buffer
)*sizeof(WCHAR
);
4718 RegSetValueExW(hkey
,szRegKeys
[i
],0,REG_SZ
,(LPSTR
)buffer
,size
);
4724 RegSetValueExW(hkey
,szWindowsInstaler
,0,REG_DWORD
,(LPSTR
)&rc
,size
);
4726 /* copy the package locally */
4727 num
= GetTickCount() & 0xffff;
4731 sprintfW(packagefile
,fmt
,num
);
4734 HANDLE handle
= CreateFileW(packagefile
,GENERIC_WRITE
, 0, NULL
,
4735 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, 0 );
4736 if (handle
!= INVALID_HANDLE_VALUE
)
4738 CloseHandle(handle
);
4741 if (GetLastError() != ERROR_FILE_EXISTS
&&
4742 GetLastError() != ERROR_SHARING_VIOLATION
)
4744 if (!(++num
& 0xffff)) num
= 1;
4745 sprintfW(packagefile
,fmt
,num
);
4746 } while (num
!= start
);
4748 create_full_pathW(path
);
4749 TRACE("Copying to local package %s\n",debugstr_w(packagefile
));
4750 CopyFileW(package
->PackagePath
,packagefile
,FALSE
);
4751 size
= strlenW(packagefile
)*sizeof(WCHAR
);
4752 RegSetValueExW(hkey
,szLocalPackage
,0,REG_SZ
,(LPSTR
)packagefile
,size
);
4755 HeapFree(GetProcessHeap(),0,productcode
);
4758 return ERROR_SUCCESS
;
4761 static UINT
ACTION_InstallExecute(MSIPACKAGE
*package
)
4765 return ERROR_INVALID_HANDLE
;
4767 for (i
= 0; i
< package
->DeferredActionCount
; i
++)
4770 action
= package
->DeferredAction
[i
];
4771 ui_actionstart(package
, action
);
4772 TRACE("Executing Action (%s)\n",debugstr_w(action
));
4773 ACTION_CustomAction(package
,action
,TRUE
);
4774 HeapFree(GetProcessHeap(),0,package
->DeferredAction
[i
]);
4776 HeapFree(GetProcessHeap(),0,package
->DeferredAction
);
4778 package
->DeferredActionCount
= 0;
4779 package
->DeferredAction
= NULL
;
4781 return ERROR_SUCCESS
;
4784 static UINT
ACTION_InstallFinalize(MSIPACKAGE
*package
)
4788 return ERROR_INVALID_HANDLE
;
4790 /* first do the same as an InstallExecute */
4791 ACTION_InstallExecute(package
);
4793 /* then handle Commit Actions */
4794 for (i
= 0; i
< package
->CommitActionCount
; i
++)
4797 action
= package
->CommitAction
[i
];
4798 ui_actionstart(package
, action
);
4799 TRACE("Executing Commit Action (%s)\n",debugstr_w(action
));
4800 ACTION_CustomAction(package
,action
,TRUE
);
4801 HeapFree(GetProcessHeap(),0,package
->CommitAction
[i
]);
4803 HeapFree(GetProcessHeap(),0,package
->CommitAction
);
4805 package
->CommitActionCount
= 0;
4806 package
->CommitAction
= NULL
;
4808 return ERROR_SUCCESS
;
4811 static UINT
ACTION_ForceReboot(MSIPACKAGE
*package
)
4813 static const WCHAR RunOnce
[] = {
4814 'S','o','f','t','w','a','r','e','\\',
4815 'M','i','c','r','o','s','o','f','t','\\',
4816 'W','i','n','d','o','w','s','\\',
4817 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4818 'R','u','n','O','n','c','e'};
4819 static const WCHAR InstallRunOnce
[] = {
4820 'S','o','f','t','w','a','r','e','\\',
4821 'M','i','c','r','o','s','o','f','t','\\',
4822 'W','i','n','d','o','w','s','\\',
4823 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4824 'I','n','s','t','a','l','l','e','r','\\',
4825 'R','u','n','O','n','c','e','E','n','t','r','i','e','s'};
4827 static const WCHAR msiexec_fmt
[] = {
4828 'C',':','\\','W','i','n','d','o','w','s','\\','S','y','s','t','e','m',
4829 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4830 '\"','%','s','\"',0};
4831 static const WCHAR install_fmt
[] = {
4832 '/','I',' ','\"','%','s','\"',' ',
4833 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4834 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4838 WCHAR squished_pc
[100];
4841 static const WCHAR szProductCode
[]=
4842 {'P','r','o','d','u','c','t','C','o','d','e',0};
4843 static const WCHAR szLUS
[] = {
4844 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0};
4845 static const WCHAR szSourceList
[] = {
4846 'S','o','u','r','c','e','L','i','s','t',0};
4847 static const WCHAR szPackageName
[] = {
4848 'P','a','c','k','a','g','e','N','a','m','e',0};
4851 return ERROR_INVALID_HANDLE
;
4853 productcode
= load_dynamic_property(package
,szProductCode
,&rc
);
4857 squash_guid(productcode
,squished_pc
);
4859 RegCreateKeyW(HKEY_LOCAL_MACHINE
,RunOnce
,&hkey
);
4860 sprintfW(buffer
,msiexec_fmt
,squished_pc
);
4862 size
= strlenW(buffer
)*sizeof(WCHAR
);
4863 RegSetValueExW(hkey
,squished_pc
,0,REG_SZ
,(LPSTR
)buffer
,size
);
4866 TRACE("Reboot command %s\n",debugstr_w(buffer
));
4868 RegCreateKeyW(HKEY_LOCAL_MACHINE
,InstallRunOnce
,&hkey
);
4869 sprintfW(buffer
,install_fmt
,productcode
,squished_pc
);
4870 RegSetValueExW(hkey
,squished_pc
,0,REG_SZ
,(LPSTR
)buffer
,size
);
4873 rc
= MSIREG_OpenUserProductsKey(productcode
,&hukey
,TRUE
);
4874 if (rc
== ERROR_SUCCESS
)
4878 RegCreateKeyW(hukey
, szSourceList
, &hukey2
);
4879 buf
= load_dynamic_property(package
,cszSourceDir
,NULL
);
4880 size
= strlenW(buf
)*sizeof(WCHAR
);
4881 RegSetValueExW(hukey2
,szLUS
,0,REG_SZ
,(LPSTR
)buf
,size
);
4882 HeapFree(GetProcessHeap(),0,buf
);
4884 buf
= strrchrW(package
->PackagePath
,'\\');
4888 size
= strlenW(buf
)*sizeof(WCHAR
);
4889 RegSetValueExW(hukey2
,szPackageName
,0,REG_SZ
,(LPSTR
)buf
,size
);
4892 RegCloseKey(hukey2
);
4894 HeapFree(GetProcessHeap(),0,productcode
);
4896 return ERROR_INSTALL_SUSPEND
;
4899 /* Msi functions that seem appropriate here */
4900 UINT WINAPI
MsiDoActionA( MSIHANDLE hInstall
, LPCSTR szAction
)
4905 TRACE(" exteral attempt at action %s\n",szAction
);
4908 return ERROR_FUNCTION_FAILED
;
4910 return ERROR_FUNCTION_FAILED
;
4912 szwAction
= strdupAtoW(szAction
);
4915 return ERROR_FUNCTION_FAILED
;
4918 rc
= MsiDoActionW(hInstall
, szwAction
);
4919 HeapFree(GetProcessHeap(),0,szwAction
);
4923 UINT WINAPI
MsiDoActionW( MSIHANDLE hInstall
, LPCWSTR szAction
)
4925 MSIPACKAGE
*package
;
4926 UINT ret
= ERROR_INVALID_HANDLE
;
4928 TRACE(" external attempt at action %s \n",debugstr_w(szAction
));
4930 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
4933 ret
= ACTION_PerformAction(package
,szAction
);
4934 msiobj_release( &package
->hdr
);
4939 UINT WINAPI
MsiGetTargetPathA( MSIHANDLE hInstall
, LPCSTR szFolder
,
4940 LPSTR szPathBuf
, DWORD
* pcchPathBuf
)
4946 TRACE("getting folder %s %p %li\n",szFolder
,szPathBuf
, *pcchPathBuf
);
4949 return ERROR_FUNCTION_FAILED
;
4951 return ERROR_FUNCTION_FAILED
;
4953 szwFolder
= strdupAtoW(szFolder
);
4956 return ERROR_FUNCTION_FAILED
;
4958 szwPathBuf
= HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf
* sizeof(WCHAR
));
4960 rc
= MsiGetTargetPathW(hInstall
, szwFolder
, szwPathBuf
,pcchPathBuf
);
4962 WideCharToMultiByte( CP_ACP
, 0, szwPathBuf
, *pcchPathBuf
, szPathBuf
,
4963 *pcchPathBuf
, NULL
, NULL
);
4965 HeapFree(GetProcessHeap(),0,szwFolder
);
4966 HeapFree(GetProcessHeap(),0,szwPathBuf
);
4971 UINT WINAPI
MsiGetTargetPathW( MSIHANDLE hInstall
, LPCWSTR szFolder
, LPWSTR
4972 szPathBuf
, DWORD
* pcchPathBuf
)
4975 UINT rc
= ERROR_FUNCTION_FAILED
;
4976 MSIPACKAGE
*package
;
4978 TRACE("(%s %p %li)\n",debugstr_w(szFolder
),szPathBuf
,*pcchPathBuf
);
4980 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
4982 return ERROR_INVALID_HANDLE
;
4983 path
= resolve_folder(package
, szFolder
, FALSE
, FALSE
, NULL
);
4984 msiobj_release( &package
->hdr
);
4986 if (path
&& (strlenW(path
) > *pcchPathBuf
))
4988 *pcchPathBuf
= strlenW(path
)+1;
4989 rc
= ERROR_MORE_DATA
;
4993 *pcchPathBuf
= strlenW(path
)+1;
4994 strcpyW(szPathBuf
,path
);
4995 TRACE("Returning Path %s\n",debugstr_w(path
));
4998 HeapFree(GetProcessHeap(),0,path
);
5004 UINT WINAPI
MsiGetSourcePathA( MSIHANDLE hInstall
, LPCSTR szFolder
,
5005 LPSTR szPathBuf
, DWORD
* pcchPathBuf
)
5011 TRACE("getting source %s %p %li\n",szFolder
,szPathBuf
, *pcchPathBuf
);
5014 return ERROR_FUNCTION_FAILED
;
5016 return ERROR_FUNCTION_FAILED
;
5018 szwFolder
= strdupAtoW(szFolder
);
5020 return ERROR_FUNCTION_FAILED
;
5022 szwPathBuf
= HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf
* sizeof(WCHAR
));
5024 rc
= MsiGetSourcePathW(hInstall
, szwFolder
, szwPathBuf
,pcchPathBuf
);
5026 WideCharToMultiByte( CP_ACP
, 0, szwPathBuf
, *pcchPathBuf
, szPathBuf
,
5027 *pcchPathBuf
, NULL
, NULL
);
5029 HeapFree(GetProcessHeap(),0,szwFolder
);
5030 HeapFree(GetProcessHeap(),0,szwPathBuf
);
5035 UINT WINAPI
MsiGetSourcePathW( MSIHANDLE hInstall
, LPCWSTR szFolder
, LPWSTR
5036 szPathBuf
, DWORD
* pcchPathBuf
)
5039 UINT rc
= ERROR_FUNCTION_FAILED
;
5040 MSIPACKAGE
*package
;
5042 TRACE("(%s %p %li)\n",debugstr_w(szFolder
),szPathBuf
,*pcchPathBuf
);
5044 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5046 return ERROR_INVALID_HANDLE
;
5047 path
= resolve_folder(package
, szFolder
, TRUE
, FALSE
, NULL
);
5048 msiobj_release( &package
->hdr
);
5050 if (path
&& strlenW(path
) > *pcchPathBuf
)
5052 *pcchPathBuf
= strlenW(path
)+1;
5053 rc
= ERROR_MORE_DATA
;
5057 *pcchPathBuf
= strlenW(path
)+1;
5058 strcpyW(szPathBuf
,path
);
5059 TRACE("Returning Path %s\n",debugstr_w(path
));
5062 HeapFree(GetProcessHeap(),0,path
);
5068 UINT WINAPI
MsiSetTargetPathA(MSIHANDLE hInstall
, LPCSTR szFolder
,
5069 LPCSTR szFolderPath
)
5072 LPWSTR szwFolderPath
;
5076 return ERROR_FUNCTION_FAILED
;
5078 return ERROR_FUNCTION_FAILED
;
5080 szwFolder
= strdupAtoW(szFolder
);
5082 return ERROR_FUNCTION_FAILED
;
5084 szwFolderPath
= strdupAtoW(szFolderPath
);
5087 HeapFree(GetProcessHeap(),0,szwFolder
);
5088 return ERROR_FUNCTION_FAILED
;
5091 rc
= MsiSetTargetPathW(hInstall
, szwFolder
, szwFolderPath
);
5093 HeapFree(GetProcessHeap(),0,szwFolder
);
5094 HeapFree(GetProcessHeap(),0,szwFolderPath
);
5099 UINT
MSI_SetTargetPathW(MSIPACKAGE
*package
, LPCWSTR szFolder
,
5100 LPCWSTR szFolderPath
)
5104 LPWSTR path2
= NULL
;
5108 TRACE("(%p %s %s)\n",package
, debugstr_w(szFolder
),debugstr_w(szFolderPath
));
5111 return ERROR_INVALID_HANDLE
;
5113 if (szFolderPath
[0]==0)
5114 return ERROR_FUNCTION_FAILED
;
5116 if (GetFileAttributesW(szFolderPath
) == INVALID_FILE_ATTRIBUTES
)
5117 return ERROR_FUNCTION_FAILED
;
5119 path
= resolve_folder(package
,szFolder
,FALSE
,FALSE
,&folder
);
5122 return ERROR_INVALID_PARAMETER
;
5124 HeapFree(GetProcessHeap(),0,folder
->Property
);
5126 len
= strlenW(szFolderPath
);
5128 if (szFolderPath
[len
-1]!='\\')
5131 folder
->Property
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
5132 strcpyW(folder
->Property
,szFolderPath
);
5133 strcatW(folder
->Property
,cszbs
);
5136 folder
->Property
= dupstrW(szFolderPath
);
5138 if (strcmpiW(path
, szFolderPath
) == 0)
5141 * Resolved Target has not really changed, so just
5142 * set this folder and do not recalculate everything.
5144 HeapFree(GetProcessHeap(),0,folder
->ResolvedTarget
);
5145 folder
->ResolvedTarget
= NULL
;
5146 path2
= resolve_folder(package
,szFolder
,FALSE
,TRUE
,NULL
);
5147 HeapFree(GetProcessHeap(),0,path2
);
5151 for (i
= 0; i
< package
->loaded_folders
; i
++)
5153 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedTarget
);
5154 package
->folders
[i
].ResolvedTarget
=NULL
;
5157 for (i
= 0; i
< package
->loaded_folders
; i
++)
5159 path2
=resolve_folder(package
, package
->folders
[i
].Directory
, FALSE
,
5161 HeapFree(GetProcessHeap(),0,path2
);
5164 HeapFree(GetProcessHeap(),0,path
);
5166 return ERROR_SUCCESS
;
5169 UINT WINAPI
MsiSetTargetPathW(MSIHANDLE hInstall
, LPCWSTR szFolder
,
5170 LPCWSTR szFolderPath
)
5172 MSIPACKAGE
*package
;
5175 TRACE("(%s %s)\n",debugstr_w(szFolder
),debugstr_w(szFolderPath
));
5177 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5178 ret
= MSI_SetTargetPathW( package
, szFolder
, szFolderPath
);
5179 msiobj_release( &package
->hdr
);
5183 /***********************************************************************
5184 * MsiGetMode (MSI.@)
5186 * Returns an internal installer state (if it is running in a mode iRunMode)
5189 * hInstall [I] Handle to the installation
5190 * hRunMode [I] Checking run mode
5191 * MSIRUNMODE_ADMIN Administrative mode
5192 * MSIRUNMODE_ADVERTISE Advertisement mode
5193 * MSIRUNMODE_MAINTENANCE Maintenance mode
5194 * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled
5195 * MSIRUNMODE_LOGENABLED Log file is writing
5196 * MSIRUNMODE_OPERATIONS Operations in progress??
5197 * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed
5198 * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation
5199 * MSIRUNMODE_CABINET Files from cabinet are installed
5200 * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is supressed
5201 * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is supressed
5202 * MSIRUNMODE_RESERVED11 Reserved
5203 * MSIRUNMODE_WINDOWS9X Running under Windows95/98
5204 * MSIRUNMODE_ZAWENABLED Demand installation is supported
5205 * MSIRUNMODE_RESERVED14 Reserved
5206 * MSIRUNMODE_RESERVED15 Reserved
5207 * MSIRUNMODE_SCHEDULED called from install script
5208 * MSIRUNMODE_ROLLBACK called from rollback script
5209 * MSIRUNMODE_COMMIT called from commit script
5212 * In the state: TRUE
5213 * Not in the state: FALSE
5217 BOOL WINAPI
MsiGetMode(MSIHANDLE hInstall
, MSIRUNMODE iRunMode
)
5219 FIXME("STUB (iRunMode=%i)\n",iRunMode
);
5224 * According to the docs, when this is called it immediately recalculates
5225 * all the component states as well
5227 UINT WINAPI
MsiSetFeatureStateA(MSIHANDLE hInstall
, LPCSTR szFeature
,
5228 INSTALLSTATE iState
)
5230 LPWSTR szwFeature
= NULL
;
5233 szwFeature
= strdupAtoW(szFeature
);
5236 return ERROR_FUNCTION_FAILED
;
5238 rc
= MsiSetFeatureStateW(hInstall
,szwFeature
, iState
);
5240 HeapFree(GetProcessHeap(),0,szwFeature
);
5245 UINT WINAPI
MsiSetFeatureStateW(MSIHANDLE hInstall
, LPCWSTR szFeature
,
5246 INSTALLSTATE iState
)
5248 MSIPACKAGE
* package
;
5251 TRACE(" %s to %i\n",debugstr_w(szFeature
), iState
);
5253 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5255 return ERROR_INVALID_HANDLE
;
5257 index
= get_loaded_feature(package
,szFeature
);
5259 return ERROR_UNKNOWN_FEATURE
;
5261 package
->features
[index
].ActionRequest
= iState
;
5263 return ERROR_SUCCESS
;
5266 UINT WINAPI
MsiGetFeatureStateA(MSIHANDLE hInstall
, LPSTR szFeature
,
5267 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5269 LPWSTR szwFeature
= NULL
;
5272 szwFeature
= strdupAtoW(szFeature
);
5274 rc
= MsiGetFeatureStateW(hInstall
,szwFeature
,piInstalled
, piAction
);
5276 HeapFree( GetProcessHeap(), 0 , szwFeature
);
5281 UINT
MSI_GetFeatureStateW(MSIPACKAGE
*package
, LPWSTR szFeature
,
5282 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5286 index
= get_loaded_feature(package
,szFeature
);
5288 return ERROR_UNKNOWN_FEATURE
;
5291 *piInstalled
= package
->features
[index
].Installed
;
5294 *piAction
= package
->features
[index
].Action
;
5296 TRACE("returning %i %i\n",*piInstalled
,*piAction
);
5298 return ERROR_SUCCESS
;
5301 UINT WINAPI
MsiGetFeatureStateW(MSIHANDLE hInstall
, LPWSTR szFeature
,
5302 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5304 MSIPACKAGE
* package
;
5307 TRACE("%ld %s %p %p\n", hInstall
, debugstr_w(szFeature
), piInstalled
,
5310 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5312 return ERROR_INVALID_HANDLE
;
5313 ret
= MSI_GetFeatureStateW(package
, szFeature
, piInstalled
, piAction
);
5314 msiobj_release( &package
->hdr
);
5318 UINT WINAPI
MsiGetComponentStateA(MSIHANDLE hInstall
, LPSTR szComponent
,
5319 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5321 LPWSTR szwComponent
= NULL
;
5324 szwComponent
= strdupAtoW(szComponent
);
5326 rc
= MsiGetComponentStateW(hInstall
,szwComponent
,piInstalled
, piAction
);
5328 HeapFree( GetProcessHeap(), 0 , szwComponent
);
5333 UINT
MSI_GetComponentStateW(MSIPACKAGE
*package
, LPWSTR szComponent
,
5334 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5338 TRACE("%p %s %p %p\n", package
, debugstr_w(szComponent
), piInstalled
,
5341 index
= get_loaded_component(package
,szComponent
);
5343 return ERROR_UNKNOWN_COMPONENT
;
5346 *piInstalled
= package
->components
[index
].Installed
;
5349 *piInstalled
= package
->components
[index
].Action
;
5351 return ERROR_SUCCESS
;
5354 UINT WINAPI
MsiGetComponentStateW(MSIHANDLE hInstall
, LPWSTR szComponent
,
5355 INSTALLSTATE
*piInstalled
, INSTALLSTATE
*piAction
)
5357 MSIPACKAGE
* package
;
5360 TRACE("%ld %s %p %p\n", hInstall
, debugstr_w(szComponent
),
5361 piInstalled
, piAction
);
5363 package
= msihandle2msiinfo(hInstall
, MSIHANDLETYPE_PACKAGE
);
5365 return ERROR_INVALID_HANDLE
;
5366 ret
= MSI_GetComponentStateW( package
, szComponent
, piInstalled
, piAction
);
5367 msiobj_release( &package
->hdr
);
5372 static UINT
ACTION_Template(MSIPACKAGE
*package
)
5376 MSIRECORD
* row
= 0;
5377 static const WCHAR ExecSeqQuery
[] = {0};
5379 rc
= MSI_DatabaseOpenViewW(package
->db
, ExecSeqQuery
, &view
);
5380 if (rc
!= ERROR_SUCCESS
)
5383 rc
= MSI_ViewExecute(view
, 0);
5384 if (rc
!= ERROR_SUCCESS
)
5386 MSI_ViewClose(view
);
5387 msiobj_release(&view
->hdr
);
5393 rc
= MSI_ViewFetch(view
,&row
);
5394 if (rc
!= ERROR_SUCCESS
)
5400 msiobj_release(&row
->hdr
);
5402 MSI_ViewClose(view
);
5403 msiobj_release(&view
->hdr
);