2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Here are helper functions formally in action.c that are used by a variaty of
23 * actions and functions.
31 #include "wine/debug.h"
34 #include "wine/unicode.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
39 static const WCHAR cszTargetDir
[] = {'T','A','R','G','E','T','D','I','R',0};
40 static const WCHAR cszDatabase
[]={'D','A','T','A','B','A','S','E',0};
42 const WCHAR cszSourceDir
[] = {'S','o','u','r','c','e','D','i','r',0};
43 const WCHAR cszRootDrive
[] = {'R','O','O','T','D','R','I','V','E',0};
44 const WCHAR cszbs
[]={'\\',0};
46 DWORD
build_version_dword(LPCWSTR version_string
)
50 DWORD rc
= 0x00000000;
53 ptr1
= version_string
;
62 ptr1
= strchrW(ptr1
,'.');
72 ptr1
= strchrW(ptr1
,'.');
82 rc
= MAKELONG(build
,MAKEWORD(minor
,major
));
83 TRACE("%s -> 0x%lx\n",debugstr_w(version_string
),rc
);
87 UINT
build_icon_path(MSIPACKAGE
*package
, LPCWSTR icon_name
,
93 static const WCHAR szInstaller
[] =
94 {'M','i','c','r','o','s','o','f','t','\\',
95 'I','n','s','t','a','l','l','e','r','\\',0};
96 static const WCHAR szFolder
[] =
97 {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
99 SystemFolder
= load_dynamic_property(package
,szFolder
,NULL
);
101 dest
= build_directory_name(3, SystemFolder
, szInstaller
, package
->ProductCode
);
103 create_full_pathW(dest
);
105 *FilePath
= build_directory_name(2, dest
, icon_name
);
107 HeapFree(GetProcessHeap(),0,SystemFolder
);
108 HeapFree(GetProcessHeap(),0,dest
);
109 return ERROR_SUCCESS
;
112 WCHAR
*load_dynamic_stringW(MSIRECORD
*row
, INT index
)
119 if (MSI_RecordIsNull(row
,index
))
122 rc
= MSI_RecordGetStringW(row
,index
,NULL
,&sz
);
124 /* having an empty string is different than NULL */
127 ret
= HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR
));
133 ret
= HeapAlloc(GetProcessHeap(),0,sz
* sizeof (WCHAR
));
134 rc
= MSI_RecordGetStringW(row
,index
,ret
,&sz
);
135 if (rc
!=ERROR_SUCCESS
)
137 ERR("Unable to load dynamic string\n");
138 HeapFree(GetProcessHeap(), 0, ret
);
144 LPWSTR
load_dynamic_property(MSIPACKAGE
*package
, LPCWSTR prop
, UINT
* rc
)
150 r
= MSI_GetPropertyW(package
, prop
, NULL
, &sz
);
151 if (r
!= ERROR_SUCCESS
&& r
!= ERROR_MORE_DATA
)
158 str
= HeapAlloc(GetProcessHeap(),0,sz
*sizeof(WCHAR
));
159 r
= MSI_GetPropertyW(package
, prop
, str
, &sz
);
160 if (r
!= ERROR_SUCCESS
)
162 HeapFree(GetProcessHeap(),0,str
);
170 int get_loaded_component(MSIPACKAGE
* package
, LPCWSTR Component
)
175 for (i
= 0; i
< package
->loaded_components
; i
++)
177 if (strcmpW(Component
,package
->components
[i
].Component
)==0)
186 int get_loaded_feature(MSIPACKAGE
* package
, LPCWSTR Feature
)
191 for (i
= 0; i
< package
->loaded_features
; i
++)
193 if (strcmpW(Feature
,package
->features
[i
].Feature
)==0)
202 int get_loaded_file(MSIPACKAGE
* package
, LPCWSTR file
)
207 for (i
= 0; i
< package
->loaded_files
; i
++)
209 if (strcmpW(file
,package
->files
[i
].File
)==0)
218 int track_tempfile(MSIPACKAGE
*package
, LPCWSTR name
, LPCWSTR path
)
226 for (i
=0; i
< package
->loaded_files
; i
++)
227 if (strcmpW(package
->files
[i
].File
,name
)==0)
230 index
= package
->loaded_files
;
231 package
->loaded_files
++;
232 if (package
->loaded_files
== 1)
233 package
->files
= HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE
));
235 package
->files
= HeapReAlloc(GetProcessHeap(),0,
236 package
->files
, package
->loaded_files
* sizeof(MSIFILE
));
238 memset(&package
->files
[index
],0,sizeof(MSIFILE
));
240 package
->files
[index
].File
= strdupW(name
);
241 package
->files
[index
].TargetPath
= strdupW(path
);
242 package
->files
[index
].Temporary
= TRUE
;
244 TRACE("Tracking tempfile (%s)\n",debugstr_w(package
->files
[index
].File
));
249 LPWSTR
resolve_folder(MSIPACKAGE
*package
, LPCWSTR name
, BOOL source
,
250 BOOL set_prop
, MSIFOLDER
**folder
)
253 LPWSTR p
, path
= NULL
;
255 TRACE("Working to resolve %s\n",debugstr_w(name
));
260 /* special resolving for Target and Source root dir */
261 if (strcmpW(name
,cszTargetDir
)==0 || strcmpW(name
,cszSourceDir
)==0)
266 check_path
= load_dynamic_property(package
,cszTargetDir
,NULL
);
269 check_path
= load_dynamic_property(package
,cszRootDrive
,NULL
);
271 MSI_SetPropertyW(package
,cszTargetDir
,check_path
);
274 /* correct misbuilt target dir */
275 path
= build_directory_name(2, check_path
, NULL
);
276 if (strcmpiW(path
,check_path
)!=0)
277 MSI_SetPropertyW(package
,cszTargetDir
,path
);
281 for (i
= 0; i
< package
->loaded_folders
; i
++)
283 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
286 *folder
= &(package
->folders
[i
]);
292 path
= load_dynamic_property(package
,cszSourceDir
,NULL
);
295 path
= load_dynamic_property(package
,cszDatabase
,NULL
);
298 p
= strrchrW(path
,'\\');
305 for (i
= 0; i
< package
->loaded_folders
; i
++)
307 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
310 *folder
= &(package
->folders
[i
]);
316 for (i
= 0; i
< package
->loaded_folders
; i
++)
318 if (strcmpW(package
->folders
[i
].Directory
,name
)==0)
322 if (i
>= package
->loaded_folders
)
326 *folder
= &(package
->folders
[i
]);
328 if (!source
&& package
->folders
[i
].ResolvedTarget
)
330 path
= strdupW(package
->folders
[i
].ResolvedTarget
);
331 TRACE(" already resolved to %s\n",debugstr_w(path
));
334 else if (source
&& package
->folders
[i
].ResolvedSource
)
336 path
= strdupW(package
->folders
[i
].ResolvedSource
);
337 TRACE(" (source)already resolved to %s\n",debugstr_w(path
));
340 else if (!source
&& package
->folders
[i
].Property
)
342 path
= build_directory_name(2, package
->folders
[i
].Property
, NULL
);
344 TRACE(" internally set to %s\n",debugstr_w(path
));
346 MSI_SetPropertyW(package
,name
,path
);
350 if (package
->folders
[i
].ParentIndex
>= 0)
352 LPWSTR parent
= package
->folders
[package
->folders
[i
].ParentIndex
].Directory
;
354 TRACE(" ! Parent is %s\n", debugstr_w(parent
));
356 p
= resolve_folder(package
, parent
, source
, set_prop
, NULL
);
359 TRACE(" TargetDefault = %s\n",
360 debugstr_w(package
->folders
[i
].TargetDefault
));
362 path
= build_directory_name(3, p
,
363 package
->folders
[i
].TargetDefault
, NULL
);
364 package
->folders
[i
].ResolvedTarget
= strdupW(path
);
365 TRACE(" resolved into %s\n",debugstr_w(path
));
367 MSI_SetPropertyW(package
,name
,path
);
371 if (package
->folders
[i
].SourceDefault
&&
372 package
->folders
[i
].SourceDefault
[0]!='.')
373 path
= build_directory_name(3, p
, package
->folders
[i
].SourceDefault
, NULL
);
376 TRACE(" (source)resolved into %s\n",debugstr_w(path
));
377 package
->folders
[i
].ResolvedSource
= strdupW(path
);
379 HeapFree(GetProcessHeap(),0,p
);
384 /* wrapper to resist a need for a full rewrite right now */
385 DWORD
deformat_string(MSIPACKAGE
*package
, LPCWSTR ptr
, WCHAR
** data
)
389 MSIRECORD
*rec
= MSI_CreateRecord(1);
392 MSI_RecordSetStringW(rec
,0,ptr
);
393 MSI_FormatRecordW(package
,rec
,NULL
,&size
);
397 *data
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
399 MSI_FormatRecordW(package
,rec
,*data
,&size
);
402 msiobj_release( &rec
->hdr
);
403 return sizeof(WCHAR
)*size
;
405 msiobj_release( &rec
->hdr
);
412 UINT
schedule_action(MSIPACKAGE
*package
, UINT script
, LPCWSTR action
)
415 LPWSTR
*newbuf
= NULL
;
416 if (script
>= TOTAL_SCRIPTS
)
418 FIXME("Unknown script requested %i\n",script
);
419 return ERROR_FUNCTION_FAILED
;
421 TRACE("Scheduling Action %s in script %i\n",debugstr_w(action
), script
);
423 count
= package
->script
->ActionCount
[script
];
424 package
->script
->ActionCount
[script
]++;
426 newbuf
= HeapReAlloc(GetProcessHeap(),0,
427 package
->script
->Actions
[script
],
428 package
->script
->ActionCount
[script
]* sizeof(LPWSTR
));
430 newbuf
= HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR
));
432 newbuf
[count
] = strdupW(action
);
433 package
->script
->Actions
[script
] = newbuf
;
435 return ERROR_SUCCESS
;
438 static void remove_tracked_tempfiles(MSIPACKAGE
* package
)
445 for (i
= 0; i
< package
->loaded_files
; i
++)
447 if (package
->files
[i
].Temporary
)
449 TRACE("Cleaning up %s\n",debugstr_w(package
->files
[i
].TargetPath
));
450 DeleteFileW(package
->files
[i
].TargetPath
);
456 /* Called when the package is being closed */
457 void ACTION_free_package_structures( MSIPACKAGE
* package
)
461 TRACE("Freeing package action data\n");
463 remove_tracked_tempfiles(package
);
465 /* No dynamic buffers in features */
466 if (package
->features
&& package
->loaded_features
> 0)
467 HeapFree(GetProcessHeap(),0,package
->features
);
469 for (i
= 0; i
< package
->loaded_folders
; i
++)
471 HeapFree(GetProcessHeap(),0,package
->folders
[i
].Directory
);
472 HeapFree(GetProcessHeap(),0,package
->folders
[i
].TargetDefault
);
473 HeapFree(GetProcessHeap(),0,package
->folders
[i
].SourceDefault
);
474 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedTarget
);
475 HeapFree(GetProcessHeap(),0,package
->folders
[i
].ResolvedSource
);
476 HeapFree(GetProcessHeap(),0,package
->folders
[i
].Property
);
478 if (package
->folders
&& package
->loaded_folders
> 0)
479 HeapFree(GetProcessHeap(),0,package
->folders
);
481 for (i
= 0; i
< package
->loaded_components
; i
++)
482 HeapFree(GetProcessHeap(),0,package
->components
[i
].FullKeypath
);
484 if (package
->components
&& package
->loaded_components
> 0)
485 HeapFree(GetProcessHeap(),0,package
->components
);
487 for (i
= 0; i
< package
->loaded_files
; i
++)
489 HeapFree(GetProcessHeap(),0,package
->files
[i
].File
);
490 HeapFree(GetProcessHeap(),0,package
->files
[i
].FileName
);
491 HeapFree(GetProcessHeap(),0,package
->files
[i
].ShortName
);
492 HeapFree(GetProcessHeap(),0,package
->files
[i
].Version
);
493 HeapFree(GetProcessHeap(),0,package
->files
[i
].Language
);
494 HeapFree(GetProcessHeap(),0,package
->files
[i
].SourcePath
);
495 HeapFree(GetProcessHeap(),0,package
->files
[i
].TargetPath
);
498 if (package
->files
&& package
->loaded_files
> 0)
499 HeapFree(GetProcessHeap(),0,package
->files
);
501 /* clean up extension, progid, class and verb structures */
502 for (i
= 0; i
< package
->loaded_classes
; i
++)
504 HeapFree(GetProcessHeap(),0,package
->classes
[i
].Description
);
505 HeapFree(GetProcessHeap(),0,package
->classes
[i
].FileTypeMask
);
506 HeapFree(GetProcessHeap(),0,package
->classes
[i
].IconPath
);
507 HeapFree(GetProcessHeap(),0,package
->classes
[i
].DefInprocHandler
);
508 HeapFree(GetProcessHeap(),0,package
->classes
[i
].DefInprocHandler32
);
509 HeapFree(GetProcessHeap(),0,package
->classes
[i
].Argument
);
510 HeapFree(GetProcessHeap(),0,package
->classes
[i
].ProgIDText
);
513 if (package
->classes
&& package
->loaded_classes
> 0)
514 HeapFree(GetProcessHeap(),0,package
->classes
);
516 for (i
= 0; i
< package
->loaded_extensions
; i
++)
518 HeapFree(GetProcessHeap(),0,package
->extensions
[i
].ProgIDText
);
521 if (package
->extensions
&& package
->loaded_extensions
> 0)
522 HeapFree(GetProcessHeap(),0,package
->extensions
);
524 for (i
= 0; i
< package
->loaded_progids
; i
++)
526 HeapFree(GetProcessHeap(),0,package
->progids
[i
].ProgID
);
527 HeapFree(GetProcessHeap(),0,package
->progids
[i
].Description
);
528 HeapFree(GetProcessHeap(),0,package
->progids
[i
].IconPath
);
531 if (package
->progids
&& package
->loaded_progids
> 0)
532 HeapFree(GetProcessHeap(),0,package
->progids
);
534 for (i
= 0; i
< package
->loaded_verbs
; i
++)
536 HeapFree(GetProcessHeap(),0,package
->verbs
[i
].Verb
);
537 HeapFree(GetProcessHeap(),0,package
->verbs
[i
].Command
);
538 HeapFree(GetProcessHeap(),0,package
->verbs
[i
].Argument
);
541 if (package
->verbs
&& package
->loaded_verbs
> 0)
542 HeapFree(GetProcessHeap(),0,package
->verbs
);
544 for (i
= 0; i
< package
->loaded_mimes
; i
++)
545 HeapFree(GetProcessHeap(),0,package
->mimes
[i
].ContentType
);
547 if (package
->mimes
&& package
->loaded_mimes
> 0)
548 HeapFree(GetProcessHeap(),0,package
->mimes
);
550 for (i
= 0; i
< package
->loaded_appids
; i
++)
552 HeapFree(GetProcessHeap(),0,package
->appids
[i
].RemoteServerName
);
553 HeapFree(GetProcessHeap(),0,package
->appids
[i
].LocalServer
);
554 HeapFree(GetProcessHeap(),0,package
->appids
[i
].ServiceParameters
);
555 HeapFree(GetProcessHeap(),0,package
->appids
[i
].DllSurrogate
);
558 if (package
->appids
&& package
->loaded_appids
> 0)
559 HeapFree(GetProcessHeap(),0,package
->appids
);
563 for (i
= 0; i
< TOTAL_SCRIPTS
; i
++)
566 for (j
= 0; j
< package
->script
->ActionCount
[i
]; j
++)
567 HeapFree(GetProcessHeap(),0,package
->script
->Actions
[i
][j
]);
569 HeapFree(GetProcessHeap(),0,package
->script
->Actions
[i
]);
572 for (i
= 0; i
< package
->script
->UniqueActionsCount
; i
++)
573 HeapFree(GetProcessHeap(),0,package
->script
->UniqueActions
[i
]);
575 HeapFree(GetProcessHeap(),0,package
->script
->UniqueActions
);
576 HeapFree(GetProcessHeap(),0,package
->script
);
579 HeapFree(GetProcessHeap(),0,package
->PackagePath
);
580 HeapFree(GetProcessHeap(),0,package
->msiFilePath
);
581 HeapFree(GetProcessHeap(),0,package
->ProductCode
);
583 /* cleanup control event subscriptions */
584 ControlEvent_CleanupSubscriptions(package
);
588 * build_directory_name()
590 * This function is to save messing round with directory names
591 * It handles adding backslashes between path segments,
592 * and can add \ at the end of the directory name if told to.
594 * It takes a variable number of arguments.
595 * It always allocates a new string for the result, so make sure
596 * to free the return value when finished with it.
598 * The first arg is the number of path segments that follow.
599 * The arguments following count are a list of path segments.
600 * A path segment may be NULL.
602 * Path segments will be added with a \ separating them.
603 * A \ will not be added after the last segment, however if the
604 * last segment is NULL, then the last character will be a \
607 LPWSTR
build_directory_name(DWORD count
, ...)
614 for(i
=0; i
<count
; i
++)
616 LPCWSTR str
= va_arg(va
,LPCWSTR
);
618 sz
+= strlenW(str
) + 1;
622 dir
= HeapAlloc(GetProcessHeap(), 0, sz
*sizeof(WCHAR
));
626 for(i
=0; i
<count
; i
++)
628 LPCWSTR str
= va_arg(va
,LPCWSTR
);
632 if( ((i
+1)!=count
) && dir
[strlenW(dir
)-1]!='\\')
638 /***********************************************************************
641 * Recursively create all directories in the path.
643 * shamelessly stolen from setupapi/queue.c
645 BOOL
create_full_pathW(const WCHAR
*path
)
651 new_path
= HeapAlloc(GetProcessHeap(), 0, (strlenW(path
) + 1) *
654 strcpyW(new_path
, path
);
656 while((len
= strlenW(new_path
)) && new_path
[len
- 1] == '\\')
657 new_path
[len
- 1] = 0;
659 while(!CreateDirectoryW(new_path
, NULL
))
662 DWORD last_error
= GetLastError();
663 if(last_error
== ERROR_ALREADY_EXISTS
)
666 if(last_error
!= ERROR_PATH_NOT_FOUND
)
672 if(!(slash
= strrchrW(new_path
, '\\')))
678 len
= slash
- new_path
;
680 if(!create_full_pathW(new_path
))
685 new_path
[len
] = '\\';
688 HeapFree(GetProcessHeap(), 0, new_path
);
692 void ui_progress(MSIPACKAGE
*package
, int a
, int b
, int c
, int d
)
696 row
= MSI_CreateRecord(4);
697 MSI_RecordSetInteger(row
,1,a
);
698 MSI_RecordSetInteger(row
,2,b
);
699 MSI_RecordSetInteger(row
,3,c
);
700 MSI_RecordSetInteger(row
,4,d
);
701 MSI_ProcessMessage(package
, INSTALLMESSAGE_PROGRESS
, row
);
702 msiobj_release(&row
->hdr
);
704 msi_dialog_check_messages(NULL
);
707 void ui_actiondata(MSIPACKAGE
*package
, LPCWSTR action
, MSIRECORD
* record
)
709 static const WCHAR Query_t
[] =
710 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
711 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
712 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',
713 ' ','\'','%','s','\'',0};
717 static const WCHAR szActionData
[] =
718 {'A','c','t','i','o','n','D','a','t','a',0};
720 if (!package
->LastAction
|| strcmpW(package
->LastAction
,action
))
722 row
= MSI_QueryGetRecord(package
->db
, Query_t
, action
);
726 if (MSI_RecordIsNull(row
,3))
728 msiobj_release(&row
->hdr
);
732 /* update the cached actionformat */
733 HeapFree(GetProcessHeap(),0,package
->ActionFormat
);
734 package
->ActionFormat
= load_dynamic_stringW(row
,3);
736 HeapFree(GetProcessHeap(),0,package
->LastAction
);
737 package
->LastAction
= strdupW(action
);
739 msiobj_release(&row
->hdr
);
742 MSI_RecordSetStringW(record
,0,package
->ActionFormat
);
744 MSI_FormatRecordW(package
,record
,message
,&size
);
746 row
= MSI_CreateRecord(1);
747 MSI_RecordSetStringW(row
,1,message
);
749 MSI_ProcessMessage(package
, INSTALLMESSAGE_ACTIONDATA
, row
);
751 ControlEvent_FireSubscribedEvent(package
,szActionData
, row
);
753 msiobj_release(&row
->hdr
);
756 BOOL
ACTION_VerifyComponentForAction(MSIPACKAGE
* package
, INT index
,
759 if (package
->components
[index
].Installed
== check
)
762 if (package
->components
[index
].ActionRequest
== check
)
768 BOOL
ACTION_VerifyFeatureForAction(MSIPACKAGE
* package
, INT index
,
771 if (package
->features
[index
].Installed
== check
)
774 if (package
->features
[index
].ActionRequest
== check
)
780 void reduce_to_longfilename(WCHAR
* filename
)
782 LPWSTR p
= strchrW(filename
,'|');
784 memmove(filename
, p
+1, (strlenW(p
+1)+1)*sizeof(WCHAR
));
787 void reduce_to_shortfilename(WCHAR
* filename
)
789 LPWSTR p
= strchrW(filename
,'|');
794 LPWSTR
create_component_advertise_string(MSIPACKAGE
* package
,
795 MSICOMPONENT
* component
, LPCWSTR feature
)
798 WCHAR productid_85
[21];
799 WCHAR component_85
[21];
801 * I have a fair bit of confusion as to when a < is used and when a > is
802 * used. I do not think i have it right...
804 * Ok it appears that the > is used if there is a guid for the compoenent
805 * and the < is used if not.
807 static WCHAR fmt1
[] = {'%','s','%','s','<',0,0};
808 static WCHAR fmt2
[] = {'%','s','%','s','>','%','s',0,0};
809 LPWSTR output
= NULL
;
812 memset(productid_85
,0,sizeof(productid_85
));
813 memset(component_85
,0,sizeof(component_85
));
815 CLSIDFromString(package
->ProductCode
, &clsid
);
817 encode_base85_guid(&clsid
,productid_85
);
819 CLSIDFromString(component
->ComponentId
, &clsid
);
820 encode_base85_guid(&clsid
,component_85
);
822 TRACE("Doing something with this... %s %s %s\n",
823 debugstr_w(productid_85
), debugstr_w(feature
),
824 debugstr_w(component_85
));
826 sz
= lstrlenW(productid_85
) + lstrlenW(feature
);
828 sz
+= lstrlenW(component_85
);
833 output
= HeapAlloc(GetProcessHeap(),0,sz
);
837 sprintfW(output
,fmt2
,productid_85
,feature
,component_85
);
839 sprintfW(output
,fmt1
,productid_85
,feature
);
844 /* update compoennt state based on a feature change */
845 void ACTION_UpdateComponentStates(MSIPACKAGE
*package
, LPCWSTR szFeature
)
848 INSTALLSTATE newstate
;
851 i
= get_loaded_feature(package
,szFeature
);
855 feature
= &package
->features
[i
];
856 newstate
= feature
->ActionRequest
;
858 for( i
= 0; i
< feature
->ComponentCount
; i
++)
860 MSICOMPONENT
* component
= &package
->components
[feature
->Components
[i
]];
862 TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n",
863 newstate
, debugstr_w(component
->Component
), component
->Installed
,
864 component
->Action
, component
->ActionRequest
);
866 if (!component
->Enabled
)
870 if (newstate
== INSTALLSTATE_LOCAL
)
872 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
873 component
->Action
= INSTALLSTATE_LOCAL
;
879 component
->ActionRequest
= newstate
;
880 component
->Action
= newstate
;
882 /*if any other feature wants is local we need to set it local*/
884 j
< package
->loaded_features
&&
885 component
->ActionRequest
!= INSTALLSTATE_LOCAL
;
888 for (k
= 0; k
< package
->features
[j
].ComponentCount
; k
++)
889 if ( package
->features
[j
].Components
[k
] ==
890 feature
->Components
[i
] )
892 if (package
->features
[j
].ActionRequest
==
895 TRACE("Saved by %s\n", debugstr_w(package
->features
[j
].Feature
));
896 component
->ActionRequest
= INSTALLSTATE_LOCAL
;
897 component
->Action
= INSTALLSTATE_LOCAL
;
904 TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n",
905 newstate
, debugstr_w(component
->Component
), component
->Installed
,
906 component
->Action
, component
->ActionRequest
);
910 UINT
register_unique_action(MSIPACKAGE
*package
, LPCWSTR action
)
913 LPWSTR
*newbuf
= NULL
;
915 if (!package
|| !package
->script
)
918 TRACE("Registering Action %s as having fun\n",debugstr_w(action
));
920 count
= package
->script
->UniqueActionsCount
;
921 package
->script
->UniqueActionsCount
++;
923 newbuf
= HeapReAlloc(GetProcessHeap(),0,
924 package
->script
->UniqueActions
,
925 package
->script
->UniqueActionsCount
* sizeof(LPWSTR
));
927 newbuf
= HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR
));
929 newbuf
[count
] = strdupW(action
);
930 package
->script
->UniqueActions
= newbuf
;
932 return ERROR_SUCCESS
;
935 BOOL
check_unique_action(MSIPACKAGE
*package
, LPCWSTR action
)
939 if (!package
|| !package
->script
)
942 for (i
= 0; i
< package
->script
->UniqueActionsCount
; i
++)
943 if (!strcmpW(package
->script
->UniqueActions
[i
],action
))
949 WCHAR
* generate_error_string(MSIPACKAGE
*package
, UINT error
, DWORD count
, ... )
951 static const WCHAR query
[] = {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ','F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ','`','E','r','r','o','r','`',' ','=',' ','%','i',0};
961 row
= MSI_QueryGetRecord(package
->db
, query
, error
);
965 rec
= MSI_CreateRecord(count
+2);
967 str
= MSI_RecordGetString(row
,1);
968 MSI_RecordSetStringW(rec
,0,str
);
969 msiobj_release( &row
->hdr
);
970 MSI_RecordSetInteger(rec
,1,error
);
973 for (i
= 0; i
< count
; i
++)
975 str
= va_arg(va
,LPCWSTR
);
976 MSI_RecordSetStringW(rec
,(i
+2),str
);
980 MSI_FormatRecordW(package
,rec
,NULL
,&size
);
984 data
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
986 MSI_FormatRecordW(package
,rec
,data
,&size
);
989 msiobj_release( &rec
->hdr
);
993 msiobj_release( &rec
->hdr
);