//----------------------------------------------------------------------------------------- // 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 #include #include #include #include #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; }