Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

632 lines
18 KiB

//-----------------------------------------------------------------------------------------
// Go to "OCM" alias for assistance on this "technology"
//
//
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#endif
#ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later.
#define _WIN32_WINNT 0x0510 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
#endif
#include <windows.h>
#include <windef.h>
#include <tchar.h>
#include <setupapi.h>
#include <shellapi.h>
#include "ocmanage.h"
#include "uddiocm.h"
#include "uddiinst.h"
#include "ocmcallback.h"
#include "appcompat.h"
#include "..\shared\common.h"
#include "resource.h"
TCHAR *ocmmsg[100] =
{
TEXT( "OC_PREINITIALIZE" ),
TEXT( "OC_INIT_COMPONENT" ),
TEXT( "OC_SET_LANGUAGE" ),
TEXT( "OC_QUERY_IMAGE" ),
TEXT( "OC_REQUEST_PAGES" ),
TEXT( "OC_QUERY_CHANGE_SEL_STATE" ),
TEXT( "OC_CALC_DISK_SPACE" ),
TEXT( "OC_QUEUE_FILE_OPS" ),
TEXT( "OC_NOTIFICATION_FROM_QUEUE" ),
TEXT( "OC_QUERY_STEP_COUNT" ),
TEXT( "OC_COMPLETE_INSTALLATION" ),
TEXT( "OC_CLEANUP" ),
TEXT( "OC_QUERY_STATE" ),
TEXT( "OC_NEED_MEDIA" ),
TEXT( "OC_ABOUT_TO_COMMIT_QUEUE" ),
TEXT( "OC_QUERY_SKIP_PAGE" ),
TEXT( "OC_WIZARD_CREATED" ),
TEXT( "OC_FILE_BUSY" ),
TEXT( "OC_EXTRA_ROUTINES" ),
TEXT( "OC_QUERY_IMAGE_EX" )
};
TCHAR *ocmpage[100] =
{
TEXT("WizPagesWelcome"),
TEXT("WizPagesMode"),
TEXT("WizPagesEarly"),
TEXT("WizPagesPrenet"),
TEXT("WizPagesPostnet"),
TEXT("WizPagesLate"),
TEXT("WizPagesFinal")
};
typedef struct
{
LPCTSTR szComponentName;
LPCTSTR szSubcomponentName;
UINT_PTR Param1;
PVOID Param2;
} OCM_CALLBACK_ARGS, *POCM_CALLBACK_ARGS;
static DWORD UddiOcmPreinitialize ( OCM_CALLBACK_ARGS& args );
static DWORD UddiOcmInitComponent ( OCM_CALLBACK_ARGS& args );
static DWORD UddiOcmChangeSelectionState( OCM_CALLBACK_ARGS& args );
static DWORD UddiOcmInstallUninstall ( OCM_CALLBACK_ARGS& args );
static DWORD UddiOcmRequestPages ( OCM_CALLBACK_ARGS& args );
static DWORD UddiOcmQueryState ( OCM_CALLBACK_ARGS& args );
static DWORD UddiOcmCalcDiskSpace ( OCM_CALLBACK_ARGS& args );
static DWORD UddiOcmQueueUDDIFiles ( OCM_CALLBACK_ARGS& args );
static DWORD UddiOcmQueryStepCount ( OCM_CALLBACK_ARGS& args );
//-----------------------------------------------------------------------------------------
HINSTANCE g_hInstance = NULL;
CUDDIInstall g_uddiComponents;
static TCHAR g_szSetupPath[ MAX_PATH ];
static TCHAR g_szUnattendPath[ MAX_PATH ];
static HINF g_hComponent;
static bool g_bUnattendMode = false;
static bool g_bPerformedCompInstall = false;
//-----------------------------------------------------------------------------------------
BOOL APIENTRY DllMain( HINSTANCE hInstance,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_hInstance = hInstance;
g_uddiComponents.SetInstance( hInstance );
ClearLog();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
//-----------------------------------------------------------------------------------------
DWORD __stdcall OcEntry(
IN LPCTSTR szComponentName,
IN LPCTSTR szSubcomponentName,
IN UINT uMsgID,
IN UINT_PTR Param1,
IN OUT PVOID Param2
)
{
if( g_bUnattendMode )
return NO_ERROR;
DWORD dwOcEntryReturn = 0;
OCM_CALLBACK_ARGS args;
args.Param1 = Param1;
args.Param2 = Param2;
args.szComponentName = szComponentName;
args.szSubcomponentName = szSubcomponentName;
MyOutputDebug( TEXT("--- Component: %15s Subcomponent: %15s Function: %s"),
szComponentName,
NULL == szSubcomponentName ? TEXT( "(NULL) ") : szSubcomponentName,
ocmmsg[uMsgID]);
switch(uMsgID)
{
case OC_PREINITIALIZE:
dwOcEntryReturn = UddiOcmPreinitialize( args );
break;
case OC_INIT_COMPONENT:
dwOcEntryReturn = UddiOcmInitComponent( args );
break;
case OC_CALC_DISK_SPACE:
dwOcEntryReturn = UddiOcmCalcDiskSpace( args );
break;
case OC_QUERY_STEP_COUNT:
dwOcEntryReturn = UddiOcmQueryStepCount( args );
break;
case OC_QUEUE_FILE_OPS:
dwOcEntryReturn = UddiOcmQueueUDDIFiles( args );
break;
case OC_ABOUT_TO_COMMIT_QUEUE:
break;
case OC_COMPLETE_INSTALLATION:
dwOcEntryReturn = UddiOcmInstallUninstall( args );
break;
case OC_WIZARD_CREATED:
break;
case OC_QUERY_STATE:
dwOcEntryReturn = UddiOcmQueryState( args );
break;
case OC_REQUEST_PAGES:
dwOcEntryReturn = UddiOcmRequestPages( args );
break;
case OC_QUERY_SKIP_PAGE:
break;
case OC_QUERY_CHANGE_SEL_STATE:
dwOcEntryReturn = UddiOcmChangeSelectionState( args );
break;
default:
break;
}
return dwOcEntryReturn;
}
//-----------------------------------------------------------------------------------------
static DWORD UddiOcmPreinitialize( OCM_CALLBACK_ARGS& args )
{
DWORD dwOcEntryReturn = 0;
#ifdef UNICODE
dwOcEntryReturn = OCFLAG_UNICODE;
#else
dwOcEntryReturn = OCFLAG_ANSI;
#endif
return dwOcEntryReturn;
}
//-----------------------------------------------------------------------------------------
static DWORD UddiOcmInitComponent( OCM_CALLBACK_ARGS& args )
{
PSETUP_INIT_COMPONENT pSetupInitComp = (PSETUP_INIT_COMPONENT) args.Param2;
SETUP_DATA setupData = pSetupInitComp->SetupData;
//
// see if we are in unattended mode
//
if( SETUPOP_BATCH & setupData.OperationFlags )
{
_tcscpy( g_szUnattendPath, pSetupInitComp->SetupData.UnattendFile );
g_bUnattendMode = true;
Log( _T("*** UDDI does not install in unattended mode ***") );
return NO_ERROR;
}
//
// grab the handle to the uddi.inf file
//
g_hComponent = pSetupInitComp->ComponentInfHandle;
//
// save a copy of the source path (to the CDROM drive)
//
// MessageBox(NULL, TEXT( "attach debugger" ), TEXT( "debug uddi" ), MB_OK);
_tcscpy( g_szSetupPath, pSetupInitComp->SetupData.SourcePath );
//
// save a copy of the callback pointers into the OCM
//
COCMCallback::SetOCMRoutines( &pSetupInitComp->HelperRoutines );
//
// if the db is already installed, the db instance name is stored in the registry.
// get it and set it for use by the web installer (if the user chooses to install the web component).
//
if( g_uddiComponents.IsInstalled( UDDI_DB ) )
{
CDBInstance dbinstances;
TCHAR szInstanceName[ 20 ];
ULONG uLen = 20;
bool bIsClustered = false;
if( dbinstances.GetUDDIDBInstanceName( NULL, szInstanceName, &uLen, &bIsClustered ) )
g_uddiComponents.SetDBInstanceName( NULL, szInstanceName, UDDI_NOT_INSTALLING_MSDE, bIsClustered );
}
//
// Finally, check the OS flavor (Enterprise, Datacenter etc.)
//
g_uddiComponents.DetectOSFlavor();
Log( _T( "OS Flavor Mask as reported by WMI: %#x" ), g_uddiComponents.GetOSSuiteMask() );
return NO_ERROR;
}
//-----------------------------------------------------------------------------------------
//
// this function is called for each component and subcomponent
//
static DWORD UddiOcmQueryState( OCM_CALLBACK_ARGS& args )
{
if( args.szSubcomponentName && args.Param1 == OCSELSTATETYPE_ORIGINAL )
{
if ( g_uddiComponents.IsInstalled( (PTCHAR) args.szSubcomponentName ) )
{
MyOutputDebug( TEXT( "Reporting that component %s is ON"), args.szSubcomponentName );
return SubcompOn;
}
else
{
MyOutputDebug( TEXT( "Reporting that component %s is OFF"), args.szSubcomponentName );
return SubcompOff;
}
}
return SubcompUseOcManagerDefault;
}
//-----------------------------------------------------------------------------------------
//
// This function is called for each component and subcomponent
// We need to verify that IIS, if installed is not setup for IIS 5 compatability mode.
// If so we will display a message to the user and uncheck the web component portion of the
// install.
//
static DWORD UddiOcmChangeSelectionState( OCM_CALLBACK_ARGS& args )
{
bool bSelected = false;
COCMCallback::QuerySelectionState( args.szSubcomponentName, bSelected );
MyOutputDebug( TEXT( "requested selection state=%08x, flags=%08x, selected=%d" ), args.Param1 , args.Param2, bSelected );
//
// ignore if the component name is null
//
if( NULL == args.szSubcomponentName )
return 0;
//
// ignore if this is the parent component
//
if( 0 == _tcscmp( args.szSubcomponentName, TEXT( "uddiservices" ) ) )
return 1;
//
// if the user has selected the web component to install AND
// IIS is set to "IIS 5.0 Application Compatibility Mode" then
// raise an error and don't allow it
//
if( 1 == args.Param1 &&
( 0 == _tcscmp( args.szSubcomponentName, TEXT( "uddiweb" ) ) ||
( 0 == _tcscmp( args.szSubcomponentName, TEXT( "uddicombo" ) ) ) ) )
{
static bool bSkipOnce = false;
//
// if the web component was selected from the parent, then suppress one
// of the two error messages (it gets called twice for some reason)
//
if( OCQ_DEPENDENT_SELECTION & ( DWORD_PTR ) args.Param2 )
{
bSkipOnce = !bSkipOnce;
if( bSkipOnce )
return 0;
}
bool bIsIIS5CompatMode;
TCHAR szMsg[ 500 ];
TCHAR szTitle[ 50 ];
LoadString( g_hInstance, IDS_TITLE, szTitle, sizeof( szTitle ) / sizeof( TCHAR ) );
HRESULT hr = IsIIS5CompatMode( &bIsIIS5CompatMode );
if( SUCCEEDED( hr ) )
{
if( bIsIIS5CompatMode )
{
//
// cannot install web component when IIS is in 5.0 compat mode
// raise error and do not accept the change
//
LoadString( g_hInstance, IDS_IIS_ISOLATION_MODE_ERROR, szMsg, sizeof( szMsg ) / sizeof( TCHAR ) );
MessageBox( NULL, szMsg, szTitle, MB_OK | MB_ICONWARNING );
Log( szMsg );
return 0;
}
}
else
{
//
// error occurred getting the app compat mode setting.
// tell the user why and tell OCM that we do not accept the change
//
// REGDB_E_CLASSNOTREG, CLASS_E_NOAGGREGATION, or E_NOINTERFACE
//
if( REGDB_E_CLASSNOTREG == hr )
{
Log( TEXT( "IIS is not installed on this machine" ) );
// This is ok 'cause IIS gets installed if the UDDI web component is selected.
}
else if( ERROR_PATH_NOT_FOUND == HRESULT_CODE( hr ) )
{
Log( TEXT( "WWW Services not installed on this machine." ) );
// This is ok 'cause WWW Services installed if the UDDI web component is selected.
}
else if( ERROR_SERVICE_DISABLED == HRESULT_CODE( hr ) )
{
LoadString( g_hInstance, IDS_IIS_SERVICE_DISABLED, szMsg, sizeof( szMsg ) / sizeof( TCHAR ) );
MessageBox( NULL, szMsg, szTitle, MB_OK | MB_ICONWARNING );
Log( szMsg );
return 0;
}
else
{
LoadString( g_hInstance, IDS_IIS_UNKNOWN_ERROR, szMsg, sizeof( szMsg ) / sizeof( TCHAR ) );
MessageBox( NULL, szMsg, szTitle, MB_OK | MB_ICONWARNING );
Log( szMsg );
return 0;
}
}
}
return 1; // indicates that this state change was ACCEPTED
}
//-----------------------------------------------------------------------------------------
static DWORD UddiOcmRequestPages( OCM_CALLBACK_ARGS& args )
{
DWORD dwOcEntryReturn = NO_ERROR;
dwOcEntryReturn = AddUDDIWizardPages(
args.szComponentName,
(WizardPagesType) args.Param1,
(PSETUP_REQUEST_PAGES) args.Param2 );
return dwOcEntryReturn; // return the number of pages that was added
}
//-----------------------------------------------------------------------------------------
static DWORD UddiOcmInstallUninstall( OCM_CALLBACK_ARGS& args )
{
DWORD dwRet = ERROR_SUCCESS;
//
// for the root component OR if someone is trying
// to install us unattended, simply return
//
if( NULL == args.szSubcomponentName )
return ERROR_SUCCESS;
//
// uddiweb "needs" iis, as commanded in uddi.inf, and the only thing we know
// for sure about OCM install order is that OCM will install IIS before it
// installs uddiweb, so let's delay installing all the UDDI components until
// the OCM calls for the installation of uddiweb, 'cause that way we can be sure
// that IIS is already installed. No, that's not a hack.
//
//
// All installation/uninstallation is deferred until this component is referenced
// This ensures that the IIS dependency is in place prior to installation of any of our
// components.
//
// TODO: Review whether this is necessary anymore. We now declare proper dependencies on netfx (.NET Framework)
// that should make this synchronization unecessary.
//
if( !g_bPerformedCompInstall )
{
g_bPerformedCompInstall = true;
Log( _T("Installing...") );
//
// Even though this method name is Install it handles both install and
// uninstall.
//
dwRet = g_uddiComponents.Install();
//
// if we need a reboot, tell the OCM
//
if( ERROR_SUCCESS_REBOOT_REQUIRED == dwRet )
{
COCMCallback::SetReboot();
//
// mute the error, as it's actualy a "success with info" code
//
dwRet = ERROR_SUCCESS;
}
else if( ERROR_SUCCESS != dwRet )
{
TCHAR szWindowsDirectory[ MAX_PATH + 1 ];
if( 0 == GetWindowsDirectory( szWindowsDirectory, MAX_PATH + 1 ) )
{
return GetLastError();
}
tstring cLogFile = szWindowsDirectory;
cLogFile.append( TEXT( "\\" ) );
cLogFile.append( UDDI_SETUP_LOG );
TCHAR szMsg[ 500 ];
TCHAR szTitle[ 50 ];
if( !LoadString( g_hInstance, IDS_INSTALL_ERROR, szMsg, sizeof( szMsg ) / sizeof( TCHAR ) ) )
return GetLastError();
if( !LoadString( g_hInstance, IDS_TITLE, szTitle, sizeof( szTitle ) / sizeof( TCHAR ) ) )
return GetLastError();
tstring cMsg = szMsg;
cMsg.append( cLogFile );
MessageBox( NULL, cMsg.c_str(), szTitle, MB_OK | MB_ICONWARNING | MB_TOPMOST );
}
else
{
//
// if we installed the Web components only, show the post-install notes
//
if( g_uddiComponents.IsInstalling( UDDI_WEB ) || g_uddiComponents.IsInstalling( UDDI_DB ) )
{
HINSTANCE hInstance = ShellExecute(
GetActiveWindow(),
TEXT( "open" ),
TEXT( "postinstall.htm" ),
NULL,
TEXT( "\\inetpub\\uddi" ),
SW_SHOWNORMAL);
}
}
}
//
// on the Standard Server, we want to fail the whole installation if one component fails
//
return ERROR_SUCCESS;
}
//-----------------------------------------------------------------------------------------
static DWORD UddiOcmQueryStepCount( OCM_CALLBACK_ARGS& args )
{
//
// if this is the main component, tell it we
// need four steps on the gauge
//
if( NULL == args.szSubcomponentName )
return 4;
return 0;
}
//-----------------------------------------------------------------------------------------
static DWORD UddiOcmQueueUDDIFiles( OCM_CALLBACK_ARGS& args )
{
if( !args.szSubcomponentName )
return 0;
HSPFILEQ hFileQueue = ( HSPFILEQ ) args.Param2;
BOOL bOK = TRUE;
DWORD dwErrCode = 0;
if( g_uddiComponents.IsInstalling( args.szSubcomponentName ) )
{
TCHAR szSectionName[ 100 ];
_stprintf( szSectionName, TEXT( "Install.%s" ), args.szSubcomponentName );
bOK = SetupInstallFilesFromInfSection(
g_hComponent, // handle to the UDDI INF file
NULL, // optional, layout INF handle
hFileQueue, // handle to the file queue
szSectionName, // name of the Install section
NULL, // optional, root path to source files
SP_COPY_NEWER | SP_COPY_NOSKIP // optional, specifies copy behavior
);
}
UDDI_PACKAGE_ID pkgSubcompID = g_uddiComponents.GetPackageID( args.szSubcomponentName );
if( pkgSubcompID == UDDI_DB || pkgSubcompID == UDDI_COMBO )
{
if( g_uddiComponents.IsInstalling( UDDI_MSDE ) )
{
//
// copy over the msde msi file, it is stored as a different
// name, and this will rename as it copies (and decomp if needed)
//
if( bOK )
{
//
// this will copy over the cab file but NOT decomp the file.
// the cab file MUST be named sqlrun.cab on the cd, because
// the SP_COPY_NODECOMP flag foils the renaming scheme built
// into the setup api's
//
bOK = SetupInstallFilesFromInfSection(
g_hComponent, // handle to the INF file
NULL, // optional, layout INF handle
hFileQueue, // handle to the file queue
TEXT( "Install.MSDE" ), // name of the Install section
NULL, // optional, root path to source files
SP_COPY_NEWER | SP_COPY_NODECOMP | SP_COPY_NOSKIP // optional, specifies copy behavior
);
}
}
}
if( !bOK )
{
dwErrCode = GetLastError();
LogError( TEXT( "Error copying the UDDI files from the Windows CD:" ), dwErrCode );
}
return dwErrCode;
}
//-----------------------------------------------------------------------------------------
static DWORD UddiOcmCalcDiskSpace( OCM_CALLBACK_ARGS& args )
{
BOOL bOK;
HDSKSPC hDiskSpace = ( HDSKSPC ) args.Param2;
tstring cSection = TEXT( "Install." );
cSection += args.szSubcomponentName;
if( args.Param1 )
{
//
// add component
//
bOK = SetupAddInstallSectionToDiskSpaceList(
hDiskSpace,
g_hComponent,
NULL,
cSection.c_str(),
0, 0);
}
else
{
//
// remove component
//
bOK = SetupRemoveInstallSectionFromDiskSpaceList(
hDiskSpace,
g_hComponent,
NULL,
cSection.c_str(),
0, 0);
}
if( !bOK )
{
LogError( TEXT( "Error adding disk space requirements" ), GetLastError() ) ;
}
return NO_ERROR;
}