Jump to content

This is a ready-only archive of the InstallSite Forum. You cannot post any new content here. / Dies ist ein Archiv des InstallSite Forums. Hier können keine neuen Beiträge veröffentlicht werden.

Detecting Component Installation

4 replies to this topic


  • Members
  • 4 posts

Posted 08 May 2001 - 05:20

I need to know how to get a list of the components to be installed so that I can pass it to a CA for deferred execution.  Is this possible?


  • Members
  • 4 posts

Posted 09 May 2001 - 09:53

I finally used a CA to create a view of the components table and then one at a time queried the installer session for the install status of each component.  Quite simple really.

The difficulty really lies in the install status of each component.  Which I worked out using trial and error.

Another thing that I noticed was that the session reported the status of the components incorrectly if the registry was disturbed during a previous install session.

I would post the code here but it is a little messy and I do not know if it would be appropriate to do so.  Stefan?

Stefan Krueger

Stefan Krueger


  • Administrators
  • 13,269 posts

Posted 09 May 2001 - 13:22

Please snd your CA to webmaster@installsite.org and I'll put it on the Custom Actions page, where it will be easier to find than in the discussion forum.
If it's a VB script please package the VBS in a ZIP, else it might be treated as a virus... (I guess most of you already know about the new VBSWG.X/Homepage virus that is spreading today?)


  • Members
  • 4 posts

Posted 30 May 2001 - 00:26

Hi, I thought that I might as well post it here too.

// notes

// revision history
// authordatenotesstatus
// Michael Chester30-May-2001initial release for testinguntested

// disclaimer
// to use the following example code it must be changed to suit your environment
// no guarantee is given or implied by the distribution of this code, either by
// the author or the distributor ( source ), it is assumed that the user is
// compotent enough to work out any problems that eventuate, no support is given

// compilation
// to compile this code you must at least:
//- include all headers and libraries provided by the MsiSDK 1.2 package
//- use UNICODE
//- use the basic_string typedef below
//- include tchar.h and all of the string libraries needed to support the
//  typedef below
// other settings may be nessecary for you to get it compiling depending on your
// compiler, see your compiler manual for details, you may need to use the
// example.def file given below if your compiler requires it

// typedef basic_string< _TCHAR, char_traits< _TCHAR >, allocator< _TCHAR > >
// tstring, *ptstring;

// example.def

//DESCRIPTION "sample custom action dll for retrieving a list of components"
//   getadddata@1

// example.cpp

// MicroSoft include for those of you with a VC compiler
#include "StdAfx.h"

UINT get_recordstring( MSIHANDLE a_record, unsigned int a_field,
  ptstring a_buffer )
// gets a string from a record entry, note that it calls the Msi function
// twice, the first time it calls the function it gets the size of the string
// to allocate, its second call is the one that retireves the string
DWORD l_size = 0;
TCHAR *l_buf = NULL;

l_res = MsiRecordGetString( a_record, a_field, _T(""), &l_size );

if( l_res == ERROR_MORE_DATA ){

l_size++; // accounting for the terminating null
l_buf = new TCHAR[l_size];
l_res = MsiRecordGetString( a_record, a_field, l_buf, &l_size );
( *a_buffer ) = l_buf;
delete [] l_buf;

else ( *a_buffer ) = _T("");

return l_res;

UINT __stdcall getadddata( MSIHANDLE a_session )
// creates a comma delimited list ( string ) of components that are currently
// marked for addition and places it in an installer property named
// SOME_CUSTOM_ACTION_NAME, it can not be called in defered execution mode,
// it will return any Windows installer error returned to it by the installer
// API causing the whole install to rollback if an error occurs
// handles to the various windows installer objects
MSIHANDLE l_record;
MSIHANDLE l_database;
// status variables to determine the component states
// string holders
TCHAR *l_end = NULL;
tstring l_item = _T("");
tstring l_list = _T("");
tstring l_name = _T("SOME_CUSTOM_ACTION_NAME");
tstring l_sql = _T("SELECT `Component` FROM `Component`");
// return value

// get a handle on our database
l_database = MsiGetActiveDatabase( a_session );
if( l_database == 0 )

// get a view of all components in the installation
l_res = MsiDatabaseOpenView( l_database, l_sql.begin( ), &l_view );
if( l_res == ERROR_SUCCESS )
l_res = MsiViewExecute( l_view, NULL );

// create our list of components
if( l_res == ERROR_SUCCESS ){

while( MsiViewFetch( l_view, &l_record ) == ERROR_SUCCESS ){

l_res = get_recordstring( l_record, 1, &l_item );

// we only want the components that are to be installed locally,
// there should really be some error checking here on the result
// of the last operation
l_res = MsiGetComponentState( a_session, l_item.begin( ),
 &l_current, &l_action );

// test to see if the component is to be added
if( ( l_current == INSTALLSTATE_ABSENT )
&& ( l_action == INSTALLSTATE_LOCAL ) ){
//alternatively if you were looking for components that are marked to
//be remove you could use the following:
//if( ( l_action == INSTALLSTATE_ABSENT )
//&& ( l_current == INSTALLSTATE_LOCAL ) )
l_list += l_item;
l_list += _T(",");


// prune off the trailing ','
if( l_list.length( ) > 0 ){

l_end = l_list.end( );
l_list.erase( --l_end );


// kill off the view and database handle used to get the list of components
l_res = MsiViewClose( l_view );
l_res = MsiCloseHandle( l_database );

// set the property
l_res = MsiSetProperty( a_session, l_name.begin( ), l_list.begin( ) );

return l_res;