|
|
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1999-2000 Microsoft Corporation
//
// Module Name:
// ScriptResource.cpp
//
// Description:
// CScriptResource class implementation.
//
// Maintained By:
// gpease 14-DEC-1999
//
//////////////////////////////////////////////////////////////////////////////
#include "pch.h"
#include <clusudef.h>
#include "ActiveScriptSite.h"
#include "ScriptResource.h"
#include "SpinLock.h"
#include "clusrtl.h"
DEFINE_THISCLASS("CScriptResource")
//
// KB: gpease 08-FEB-2000
//
// The Generic Scripting Resource uses a separate working thread to do all
// calls into the Script. This is because the Scripting Host Engines require
// only the creating thread to call them (remember, scripting is designed
// to be used in a user mode application where usually the UI thread runs
// the script). To make this possible, we serialize the threads entering the
// the script using a user-mode spinlock (m_lockSerialize). We then use two events
// to signal the "worker thread" (m_EventWait) and to signal when the "worker
// thread" has completed the task (m_EventDone).
//
// LooksAlive is implemented by returning the last result of a LooksAlive. It
// will start the "worker thread" doing the LooksAlive, but not wait for the
// thread to return the result. Because of this, all the other threads must
// make sure that the "Done Event" (m_EventDone) is signalled before writing
// into the common buffers (m_msg and m_hr).
//
//////////////////////////////////////////////////////////////////////////////
//
// LPUNKNOWN
// CScriptResource_CreateInstance( void )
//
// Description:
// Creates an intialized instance of CScriptResource.
//
// Arguments:
// None.
//
// Return Values:
// NULL - Failure to create or initialize.
// valid pointer to a CScriptResource.
//
//////////////////////////////////////////////////////////////////////////////
CScriptResource * CScriptResource_CreateInstance( LPCWSTR pszNameIn, HKEY hkeyIn, RESOURCE_HANDLE hResourceIn ) { TraceFunc( "CScriptResource_CreateInstance( )\n" );
CScriptResource * lpcc = new CScriptResource( ); if ( lpcc != NULL ) { HRESULT hr = THR( lpcc->Init( pszNameIn, hkeyIn, hResourceIn ) ); if ( SUCCEEDED( hr ) ) { RETURN( lpcc ); } // if: success
delete lpcc;
} // if: got object
RETURN(NULL); } //*** CScriptResource_CreateInstance( )
//////////////////////////////////////////////////////////////////////////////
//
// Constructor
//
//////////////////////////////////////////////////////////////////////////////
CScriptResource::CScriptResource( ) : m_dispidOpen(DISPID_UNKNOWN), m_dispidClose(DISPID_UNKNOWN), m_dispidOnline(DISPID_UNKNOWN), m_dispidOffline(DISPID_UNKNOWN), m_dispidTerminate(DISPID_UNKNOWN), m_dispidLooksAlive(DISPID_UNKNOWN), m_dispidIsAlive(DISPID_UNKNOWN) { TraceClsFunc1( "%s( )\n", __THISCLASS__ ); Assert( m_cRef == 0 );
TraceFuncExit( ); } //*** constructor
//////////////////////////////////////////////////////////////////////////////
//
// Destructor
//
//////////////////////////////////////////////////////////////////////////////
CScriptResource::~CScriptResource( ) { TraceClsFunc1( "~%s( )\n", __THISCLASS__ );
HRESULT hr;
CSpinLock SpinLock( &m_lockSerialize, INFINITE );
//
// Make sure no one else has this lock.... else why are we going away?
//
hr = SpinLock.AcquireLock( ); Assert( hr == S_OK );
//
// Kill the worker thread.
//
if ( m_hThread != NULL ) { // Tell it to DIE
m_msg = msgDIE;
// Signal the event.
SetEvent( m_hEventWait );
// Wait for it to happen. This shouldn't take long at all.
WaitForSingleObject( m_hThread, 30000 ); // 30 seconds
// Cleanup the handle.
CloseHandle( m_hThread ); }
if ( m_hEventDone != NULL ) { CloseHandle( m_hEventDone ); }
if ( m_hEventWait != NULL ) { CloseHandle( m_hEventWait ); } if ( m_pszName != NULL ) { TraceFree( m_pszName ); } // if: m_pszName
if ( m_hkeyParams != NULL ) { ClusterRegCloseKey( m_hkeyParams ); } // if: m_hkeyParams
#if defined(DEBUG)
//
// Make the debug build happy. Not needed in RETAIL.
//
SpinLock.ReleaseLock( ); #endif // defined(DEBUG)
TraceFuncExit( );
} //*** destructor
//////////////////////////////////////////////////////////////////////////////
//
// HRESULT
// CScriptResource::Init(
// LPCWSTR pszNameIn,
// HKEY hkeyIn,
// RESOURCE_HANDLE hResourceIn
// )
//
// Description:
// Initializes the class.
//
// Arguments:
// pszNameIn - Name of resource instance.
// hkeyIn - The cluster key root for this resource instance.
// hResourceIn - The hResource for this instance.
//
// Return Value:
// S_OK -
// Success.
// HRESULT_FROM_WIN32( ) error -
// if Win32 call failed.
// E_OUTOFMEMORY -
// Out of memory.
// other HRESULT errors.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CScriptResource::Init( LPCWSTR pszNameIn, HKEY hkeyIn, RESOURCE_HANDLE hResourceIn ) { TraceClsFunc1( "Init( pszNameIn = '%s' )\n", pszNameIn );
DWORD dwErr;
HRESULT hr = S_OK;
// IUnknown
AddRef( );
// Other
m_hResource = hResourceIn; Assert( m_pszName == NULL ); Assert( m_pszScriptFilePath == NULL ); Assert( m_pszScriptEngine == NULL ); Assert( m_hEventWait == NULL ); Assert( m_hEventDone == NULL ); Assert( m_lockSerialize == FALSE );
//
// Create some event to wait on.
//
// scripting engine thread wait event
m_hEventWait = CreateEvent( NULL, TRUE, FALSE, NULL ); if ( m_hEventWait == NULL ) goto Win32Error;
// task completion event
m_hEventDone = CreateEvent( NULL, TRUE, FALSE, NULL ); if ( m_hEventDone == NULL ) goto Win32Error;
//
// Copy the resource name.
//
m_pszName = TraceStrDup( pszNameIn ); if ( m_pszName == NULL ) goto OutOfMemory;
//
// Open the parameters key.
//
dwErr = ClusterRegOpenKey( hkeyIn, L"Parameters", KEY_ALL_ACCESS, &m_hkeyParams ); if ( dwErr != ERROR_SUCCESS ) { TW32( dwErr ); hr = HRESULT_FROM_WIN32( dwErr ); goto Error; } // if: failed
//
// Create the scripting engine thread.
//
m_hThread = CreateThread( NULL, 0, &S_ThreadProc, this, 0, &m_dwThreadId ); if ( m_hThread == NULL ) goto Win32Error;
Cleanup: //
// All class variable clean up should be done in the destructor.
//
HRETURN( hr );
Error: LogError( hr ); goto Cleanup;
OutOfMemory: hr = E_OUTOFMEMORY; goto Error;
Win32Error: dwErr = GetLastError( ); TW32( dwErr ); hr = HRESULT_FROM_WIN32( dwErr ); goto Error;
} //*** Init( )
//****************************************************************************
//
// IUnknown
//
//****************************************************************************
//////////////////////////////////////////////////////////////////////////////
//
// STDMETHODIMP
// CScriptResource::[IUnknown] QueryInterface(
// REFIID riid,
// LPVOID * ppv
// )
//
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CScriptResource::QueryInterface( REFIID riid, LPVOID * ppv ) { TraceClsFunc1( "[IUnknown] QueryInterface( riid, ppv = 0x%08x )\n", ppv );
HRESULT hr = E_NOINTERFACE;
if ( IsEqualIID( riid, IID_IUnknown ) ) { *ppv = TraceInterface( __THISCLASS__, IUnknown, static_cast< IUnknown* >( this ), 0 ); hr = S_OK; } // if: IUnknown
if ( SUCCEEDED( hr ) ) { ((IUnknown *) *ppv)->AddRef( ); } // if: success
QIRETURN( hr, riid );
} //*** QueryInterface( )
//////////////////////////////////////////////////////////////////////////////
//
// STDMETHODIMP_( ULONG )
// CScriptResource::[IUnknown] AddRef( void )
//
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_( ULONG ) CScriptResource::AddRef( void ) { TraceClsFunc( "[IUnknown] AddRef( )\n" );
LONG cRef = InterlockedIncrement( &m_cRef );
RETURN( cRef );
} //*** AddRef( )
//////////////////////////////////////////////////////////////////////////////
//
// STDMETHODIMP_( ULONG )
// CScriptResource::[IUnknown] Release( void )
//
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_( ULONG ) CScriptResource::Release( void ) { TraceClsFunc( "[IUnknown] Release( )\n" );
LONG cRef = InterlockedDecrement( &m_cRef );
if ( cRef == 0 ) { TraceDo( delete this ); } // if: reference count decremented to zero
RETURN( cRef );
} //*** Release( )
//****************************************************************************
//
// Publics
//
//****************************************************************************
//////////////////////////////////////////////////////////////////////////////
//
// STDMETHODIMP
// CScriptResource::Close(
// )
//
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CScriptResource::Close( ) { TraceClsFunc( "Close( )\n" );
HRESULT hr;
hr = THR( WaitForMessageToComplete( msgCLOSE ) );
HRETURN( hr );
} //*** Close( )
//////////////////////////////////////////////////////////////////////////////
//
// STDMETHODIMP
// CScriptResource::Open(
// )
//
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CScriptResource::Open( ) { TraceClsFunc( "Open( )\n" );
HRESULT hr;
hr = THR( WaitForMessageToComplete( msgOPEN ) );
// CMCM:+ 19-Dec-2000 commented this out to make the DBG PRINT quiet since we now return ERROR_RETRY
// HRETURN( hr );
return hr;
} //*** Open( )
//////////////////////////////////////////////////////////////////////////////
//
// STDMETHODIMP
// CScriptResource::Online(
// )
//
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CScriptResource::Online( ) { TraceClsFunc( "Online( )\n" );
HRESULT hr;
hr = THR( WaitForMessageToComplete( msgONLINE ) );
HRETURN( hr ); } //*** Online( )
//////////////////////////////////////////////////////////////////////////////
//
// STDMETHODIMP
// CScriptResource::Offline(
// )
//
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CScriptResource::Offline( ) { TraceClsFunc( "Offline( )\n" );
HRESULT hr;
hr = THR( WaitForMessageToComplete( msgOFFLINE ) );
HRETURN( hr ); } //*** Offline( )
//////////////////////////////////////////////////////////////////////////////
//
// STDMETHODIMP
// CScriptResource::Terminate(
// )
//
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CScriptResource::Terminate( ) { TraceClsFunc( "Terminate( )\n" );
HRESULT hr;
hr = THR( WaitForMessageToComplete( msgTERMINATE ) );
HRETURN( hr ); } //*** Terminate( )
//////////////////////////////////////////////////////////////////////////////
//
// STDMETHODIMP
// CScriptResource::LooksAlive(
// )
//
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CScriptResource::LooksAlive( ) { TraceClsFunc( "LooksAlive( )\n" );
HRESULT hr; BOOL b; DWORD dw;
CSpinLock SerializeLock( &m_lockSerialize, INFINITE );
//
// Acquire the serialization lock.
//
hr = THR( SerializeLock.AcquireLock( ) ); if ( FAILED( hr ) ) { //
// Can't "goto Error" because we didn't acquire the lock.
//
LogError( hr ); goto Cleanup; }
//
// Wait for the script thread to be "done."
//
dw = WaitForSingleObject( m_hEventDone, INFINITE ); if ( dw != WAIT_OBJECT_0 ) goto Win32Error;
//
// Reset the done event to indicate that the thread is not busy.
//
b = ResetEvent( m_hEventDone ); if ( !b ) goto Win32Error;
//
// Store the message in the common memory buffer.
//
m_msg = msgLOOKSALIVE;
//
// Signal the script thread to process the message, but don't wait for
// it to complete.
//
dw = SetEvent( m_hEventWait );
if ( m_fLastLooksAlive ) { hr = S_OK; } else { hr = S_FALSE; }
ReleaseLockAndCleanup: SerializeLock.ReleaseLock( );
Cleanup: HRETURN( hr );
Error: LogError( hr ); goto ReleaseLockAndCleanup;
Win32Error: hr = HRESULT_FROM_WIN32( GetLastError( ) ); goto Error;
} //*** LooksAlive( )
//////////////////////////////////////////////////////////////////////////////
//
// STDMETHODIMP
// CScriptResource::IsAlive(
// )
//
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CScriptResource::IsAlive( ) { TraceClsFunc( "IsAlive( )\n" );
HRESULT hr; hr = THR( WaitForMessageToComplete( msgISALIVE ) );
HRETURN( hr ); } //*** IsAlive( )
//****************************************************************************
//
// Privates
//
//****************************************************************************
//////////////////////////////////////////////////////////////////////////////
//
// HRESULT
// CScriptResource::WaitForMessageToComplete(
// SMESSAGE msgIn
// )
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CScriptResource::WaitForMessageToComplete( EMESSAGE msgIn ) { TraceClsFunc( "WaitForMessageToComplete( )\n" );
HRESULT hr; BOOL b; DWORD dw;
CSpinLock SerializeLock( &m_lockSerialize, INFINITE );
//
// Acquire the serialization lock.
//
hr = THR( SerializeLock.AcquireLock( ) ); if ( FAILED( hr ) ) { //
// Can't "goto Error" because we didn't acquire the lock.
//
LogError( hr ); goto Cleanup; }
//
// Wait for the script thread to be "done."
//
dw = WaitForSingleObject( m_hEventDone, INFINITE ); if ( dw != WAIT_OBJECT_0 ) goto Win32Error;
//
// Reset the done event to indicate that the thread is not busy.
//
b = ResetEvent( m_hEventDone ); if ( !b ) goto Win32Error;
//
// Store the message in the common memory buffer.
//
m_msg = msgIn;
//
// Signal the script thread to process the message.
//
b = SetEvent( m_hEventWait ); if ( !b ) goto Win32Error;
//
// Wait for the thread to complete.
//
dw = WaitForSingleObject( m_hEventDone, INFINITE ); if ( dw != WAIT_OBJECT_0 ) goto Win32Error;
//
// Get the result of the task from the common buffer.
//
hr = m_hr;
ReleaseLockAndCleanup: SerializeLock.ReleaseLock( );
Cleanup: HRETURN( hr );
Error: LogError( hr ); goto ReleaseLockAndCleanup;
Win32Error: hr = HRESULT_FROM_WIN32( GetLastError( ) ); goto Error;
} //*** WaitForMessageToComplete( )
//////////////////////////////////////////////////////////////////////////////
//
// STDMETHODIMP
// CScriptResource::LogError(
// HRESULT hrIn
// )
//
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CScriptResource::LogError( HRESULT hrIn ) { TraceClsFunc1( "LogError( hrIn = 0x%08x )\n", hrIn );
TraceMsg( mtfCALLS, "%s failed. HRESULT: 0x%08x\n", m_pszName, hrIn );
(ClusResLogEvent)( m_hResource, LOG_ERROR, L"HRESULT: 0x%1!08x!\n", hrIn );
HRETURN( S_OK );
} //*** LogError( )
//////////////////////////////////////////////////////////////////////////////
//
// STDMETHODIMP
// CScriptResource::LogScriptError(
// EXCEPINFO ei
// )
//
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CScriptResource::LogScriptError( EXCEPINFO ei ) { TraceClsFunc( "LogScriptError( ... )\n" );
HRESULT hr;
if ( ei.pfnDeferredFillIn != NULL ) { hr = THR( ei.pfnDeferredFillIn( &ei ) ); }
TraceMsg( mtfCALLS, "%s failed.\nError: %u\nSource: %s\nDescription: %s\n", m_pszName, ( ei.wCode == 0 ? ei.scode : ei.wCode ), ( ei.bstrSource == NULL ? L"<null>" : ei.bstrSource ), ( ei.bstrDescription == NULL ? L"<null>" : ei.bstrDescription ) ); (ClusResLogEvent)( m_hResource, LOG_ERROR, L"Error: %1!u! - Description: %2 (Source: %3)\n", ( ei.wCode == 0 ? ei.scode : ei.wCode ), ( ei.bstrDescription == NULL ? L"<null>" : ei.bstrDescription ), ( ei.bstrSource == NULL ? L"<null>" : ei.bstrSource ) ); HRETURN( S_OK ); } //*** LogScriptError( )
//////////////////////////////////////////////////////////////////////////////
//
// HRESULT
// CScriptResource::OnOpen(
// )
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CScriptResource::OnOpen( ) { TraceClsFunc( "OnOpen( ... )\n" );
HRESULT hr = S_OK; hr = HRESULT_FROM_WIN32( ERROR_RETRY ); (ClusResLogEvent)( m_hResource, LOG_INFORMATION, L"Leave OnOpen without calling connect. Fail call so we don't try to use it.\n"); return hr;
} //*** OnOpen( )
//////////////////////////////////////////////////////////////////////////////
//
// HRESULT
// CScriptResource::OnClose(
// )
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CScriptResource::OnClose( ) { TraceClsFunc( "OnClose( )\n" );
HRESULT hr; EXCEPINFO ei; VARIANT varResult;
DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };
VariantInit( &varResult );
// Assert( m_pidm != NULL );
if ( m_pidm != NULL && m_dispidClose != DISPID_UNKNOWN ) { hr = THR( m_pidm->Invoke( m_dispidClose, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, &varResult, &ei, NULL ) ); } else { hr = S_OK; } if ( hr == DISP_E_EXCEPTION ) { LogScriptError( ei ); } else if ( hr == DISP_E_MEMBERNOTFOUND ) { //
// No-op
//
hr = S_OK; } else if ( FAILED( hr ) ) { LogError( hr ); }
VariantClear( &varResult );
//
// Disconnect script engine. Note that it may not be connected
// but DoDisconnect is safe to call either way.
//
DoDisconnect( );
HRETURN( hr ); } //*** OnClose( )
//////////////////////////////////////////////////////////////////////////////
//
// HRESULT
// CScriptResource::OnOnline(
// )
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CScriptResource::OnOnline( ) { TraceClsFunc( "OnOnline( ... )\n" );
HRESULT hr; DWORD dwErr; DWORD cbSize; DWORD dwLow; DWORD dwRead;
LPWSTR pszCommand; EXCEPINFO ei; LPWSTR pszScriptFilePathTmp = NULL;
BOOL b; BOOL bDoneConnect = FALSE; VARIANT varResult;
HANDLE hFile = INVALID_HANDLE_VALUE;
LPWSTR pszScriptName = NULL; LPSTR paszText = NULL; LPWSTR pszScriptText = NULL;
VariantInit( &varResult );
DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };
//
// Figure out how big the filepath is.
//
dwErr = TW32( ClusterRegQueryValue( m_hkeyParams, CLUSREG_NAME_GENSCRIPT_SCRIPT_FILEPATH, NULL, NULL, &cbSize ) ); if ( dwErr != ERROR_SUCCESS ) { hr = HRESULT_FROM_WIN32( dwErr ); goto Error; } // if: failed
//
// Make a buffer big enough.
//
cbSize += sizeof(L"");
pszScriptFilePathTmp = reinterpret_cast<LPWSTR>( TraceAlloc( LMEM_FIXED, cbSize ) ); if ( pszScriptFilePathTmp == NULL ) goto OutOfMemory;
//
// Grab it for real this time,
//
dwErr = TW32( ClusterRegQueryValue( m_hkeyParams, CLUSREG_NAME_GENSCRIPT_SCRIPT_FILEPATH, NULL, reinterpret_cast<LPBYTE>( pszScriptFilePathTmp ), &cbSize ) ); if ( dwErr != ERROR_SUCCESS ) { hr = HRESULT_FROM_WIN32( dwErr ); goto Error; } //
// If we have some old data from before then free this first.
//
if ( m_pszScriptFilePath != NULL ) { LocalFree( m_pszScriptFilePath ); }
m_pszScriptFilePath = ClRtlExpandEnvironmentStrings( pszScriptFilePathTmp ); if ( m_pszScriptFilePath == NULL ) { hr = HRESULT_FROM_WIN32( GetLastError( ) ); goto Error; } hr = DoConnect (m_pszScriptFilePath); if ( FAILED( hr ) ) { goto Error; } bDoneConnect = TRUE;
//
// Open the script file.
//
hFile = CreateFile( m_pszScriptFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); if ( hFile == INVALID_HANDLE_VALUE ) { hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) ); goto Error; } // if: failed to open
//
// Figure out its size.
//
dwLow = GetFileSize( hFile, NULL ); if ( dwLow == -1 ) { hr = THR( HRESULT_FROM_WIN32( GetLastError( ) ) ); goto Error; } // if: failed to figure out size
else if ( dwLow == -2 ) goto OutOfMemory;
//
// Make a buffer big enough to hold it.
//
dwLow++; // add one for trailing NULL.
paszText = reinterpret_cast<LPSTR>( TraceAlloc( LMEM_FIXED, dwLow ) ); if ( paszText == NULL ) goto OutOfMemory;
//
// Read the script into memory.
//
b = ReadFile( hFile, paszText, dwLow - 1, &dwRead, NULL ); if ( !b ) { hr = HRESULT_FROM_WIN32( TW32( GetLastError( ) ) ); goto Error; } // if: failed
if ( dwRead == - 1 ) goto OutOfMemory; if ( dwLow - 1 != dwRead ) goto OutOfMemory; // TODO: figure out a better error code.
//
// Make sure it is terminated.
//
paszText[ dwRead ] = L'\0';
//
// Make a buffer to convert the text into UNICODE.
//
dwRead++; pszScriptText = reinterpret_cast<LPWSTR>( TraceAlloc( LMEM_FIXED, dwRead * sizeof(WCHAR) ) ); if ( pszScriptText == NULL ) goto OutOfMemory;
//
// Convert it to UNICODE.
//
Assert( lstrlenA( paszText ) + 1 == (signed)dwRead ); mbstowcs( pszScriptText, paszText, dwRead );
//
// Load the script into the engine for pre-parsing.
//
hr = THR( m_pasp->ParseScriptText( pszScriptText, NULL, NULL, NULL, 0, 0, 0, &varResult, &ei ) ); if ( hr == DISP_E_EXCEPTION ) goto ErrorWithExcepInfo; else if ( FAILED( hr ) ) goto Error;
VariantClear( &varResult );
Assert( m_pidm != NULL );
//
// Get DISPIDs for each method we will call.
//
pszCommand = L"Online"; hr = THR( m_pidm->GetIDsOfNames( IID_NULL, &pszCommand, 1, LOCALE_USER_DEFAULT, &m_dispidOnline ) ); if ( hr == DISP_E_UNKNOWNNAME ) { m_dispidOnline = DISPID_UNKNOWN; } else if ( FAILED( hr ) ) { goto Error; }
pszCommand = L"Close"; hr = THR( m_pidm->GetIDsOfNames( IID_NULL, &pszCommand, 1, LOCALE_USER_DEFAULT, &m_dispidClose ) ); if ( hr == DISP_E_UNKNOWNNAME ) { m_dispidClose = DISPID_UNKNOWN; } else if ( FAILED( hr ) ) { goto Error; }
pszCommand = L"Offline"; hr = THR( m_pidm->GetIDsOfNames( IID_NULL, &pszCommand, 1, LOCALE_USER_DEFAULT, &m_dispidOffline ) ); if ( hr == DISP_E_UNKNOWNNAME ) { m_dispidOffline = DISPID_UNKNOWN; } else if ( FAILED( hr ) ) { goto Error; }
pszCommand = L"Terminate"; hr = THR( m_pidm->GetIDsOfNames( IID_NULL, &pszCommand, 1, LOCALE_USER_DEFAULT, &m_dispidTerminate ) ); if ( hr == DISP_E_UNKNOWNNAME ) { m_dispidTerminate = DISPID_UNKNOWN; } else if ( FAILED( hr ) ) { goto Error; }
pszCommand = L"LooksAlive"; hr = THR( m_pidm->GetIDsOfNames( IID_NULL, &pszCommand, 1, LOCALE_USER_DEFAULT, &m_dispidLooksAlive ) ); if ( hr == DISP_E_UNKNOWNNAME ) { m_dispidLooksAlive = DISPID_UNKNOWN; } else if ( FAILED( hr ) ) { goto Error; }
pszCommand = L"IsAlive"; hr = THR( m_pidm->GetIDsOfNames( IID_NULL, &pszCommand, 1, LOCALE_USER_DEFAULT, &m_dispidIsAlive ) ); if ( hr == DISP_E_UNKNOWNNAME ) { m_dispidIsAlive = DISPID_UNKNOWN; } else if ( FAILED( hr ) ) { goto Error; }
//
// Invoke the Online function.
//
if ( m_dispidOnline != DISPID_UNKNOWN ) { hr = THR( m_pidm->Invoke( m_dispidOnline, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, &varResult, &ei, NULL ) ); if ( hr == DISP_E_EXCEPTION ) { LogScriptError( ei ); } else if ( hr == DISP_E_MEMBERNOTFOUND ) { //
// No-op
//
hr = S_OK; } else if ( FAILED( hr ) ) { LogError( hr ); } }
//
// Assume the resource LooksAlive...
//
m_fLastLooksAlive = TRUE;
//
// TODO: gpease 16-DEC-1999
// Record and process the result of the Online call.
//
Cleanup: VariantClear( &varResult );
if ( pszScriptFilePathTmp ) { TraceFree( pszScriptFilePathTmp ); } // if: pszScriptFilePathTmp
if ( paszText != NULL ) { TraceFree( paszText ); } // if: paszText
if ( pszScriptText != NULL ) { TraceFree( pszScriptText ); } // if: pszScriptText;
if ( hFile != INVALID_HANDLE_VALUE ) { CloseHandle( hFile ); } // if: hFile
HRETURN( hr ); Error: LogError( hr ); if ( bDoneConnect == TRUE ) { DoDisconnect( ); } goto Cleanup; ErrorWithExcepInfo: LogScriptError( ei ); goto Cleanup; OutOfMemory: hr = E_OUTOFMEMORY; goto Cleanup; } //*** OnOnline( )
//////////////////////////////////////////////////////////////////////////////
//
// HRESULT
// CScriptResource::OnOffline(
// )
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CScriptResource::OnOffline( ) { TraceClsFunc( "OnOffline( ... )\n" );
HRESULT hr;
EXCEPINFO ei; VARIANT varResult;
DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };
VariantInit( &varResult );
Assert( m_pidm != NULL );
if ( m_pidm != NULL && m_dispidOffline != DISPID_UNKNOWN ) { hr = THR( m_pidm->Invoke( m_dispidOffline, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, &varResult, &ei, NULL ) ); } else { hr = S_OK; } if ( hr == DISP_E_EXCEPTION ) { LogScriptError( ei ); } else if ( hr == DISP_E_MEMBERNOTFOUND ) { //
// No-op
//
hr = S_OK; } else if ( FAILED( hr ) ) { LogError( hr ); }
VariantClear( &varResult );
//
// Tear down the scripting engine association as it is recreated in OnOnline.
//
DoDisconnect( );
HRETURN( hr ); } //*** OnOffline( )
//////////////////////////////////////////////////////////////////////////////
//
// HRESULT
// CScriptResource::OnTerminate(
// )
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CScriptResource::OnTerminate( ) { TraceClsFunc( "OnTerminate( ... )\n" );
HRESULT hr;
EXCEPINFO ei; VARIANT varResult;
DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };
VariantInit( &varResult );
// Assert( m_pidm != NULL );
if ( m_pidm != NULL && m_dispidTerminate != DISPID_UNKNOWN ) { hr = THR( m_pidm->Invoke( m_dispidTerminate, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, &varResult, &ei, NULL ) ); } else { hr = S_OK; } if ( hr == DISP_E_EXCEPTION ) { LogScriptError( ei ); } else if ( hr == DISP_E_MEMBERNOTFOUND ) { //
// No-op
//
hr = S_OK; } else if ( FAILED( hr ) ) { LogError( hr ); } HRETURN( hr ); } //*** OnTerminate( )
//////////////////////////////////////////////////////////////////////////////
//
// HRESULT
// CScriptResource::OnLooksAlive(
// )
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CScriptResource::OnLooksAlive( ) { TraceClsFunc( "OnLooksAlive( ... )\n" );
HRESULT hr;
EXCEPINFO ei; VARIANT varResult;
DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };
VariantInit( &varResult );
Assert( m_pidm != NULL );
if ( m_pidm != NULL && m_dispidLooksAlive != DISPID_UNKNOWN ) { hr = THR( m_pidm->Invoke( m_dispidLooksAlive, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, &varResult, &ei, NULL ) ); } else { (ClusResLogEvent)( m_hResource, LOG_ERROR, L"%1 did not implement Function LooksAlive( ). This is a required function.\n", m_pszName ); hr = DISP_E_MEMBERNOTFOUND; goto Cleanup; } if ( hr == DISP_E_EXCEPTION ) { LogScriptError( ei ); goto Cleanup; } else if ( FAILED( hr ) ) { LogError( hr ); goto Cleanup; }
if ( V_VT( &varResult ) == VT_BOOL ) { if ( !V_BOOL( &varResult ) ) { hr = S_FALSE; } // if: not alive
} // if: correct type returned
else { hr = THR( E_INVALIDARG ); LogError( hr ); } // else: failed
Cleanup: VariantClear( &varResult );
//
// Only if the result of this function is S_OK is the resource
// considered alive.
//
if ( hr == S_OK ) { m_fLastLooksAlive = TRUE; } // if: S_OK
else { m_fLastLooksAlive = FALSE; } // else: failed
HRETURN( hr ); } //*** OnLooksAlive( )
//////////////////////////////////////////////////////////////////////////////
//
// HRESULT
// CScriptResource::OnIsAlive(
// )
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CScriptResource::OnIsAlive( ) { TraceClsFunc( "IsAlive( ... )\n" );
HRESULT hr;
EXCEPINFO ei; VARIANT varResult;
DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };
VariantInit( &varResult );
if ( m_pidm != NULL && m_dispidIsAlive != DISPID_UNKNOWN ) { hr = THR( m_pidm->Invoke( m_dispidIsAlive, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, &varResult, &ei, NULL ) ); } else { (ClusResLogEvent)( m_hResource, LOG_ERROR, L"%1 did not implement Function IsAlive( ). This is a required function.\n", m_pszName ); hr = DISP_E_MEMBERNOTFOUND; goto Cleanup; } if ( hr == DISP_E_EXCEPTION ) { LogScriptError( ei ); goto Cleanup; } else if ( FAILED( hr ) ) { LogError( hr ); goto Cleanup; }
if ( V_VT( &varResult ) == VT_BOOL ) { if ( !V_BOOL( &varResult ) ) { hr = S_FALSE; } // if: not alive
} // if: correct type returned
else { hr = THR( E_INVALIDARG ); LogError( hr ); } // else: failed
Cleanup: VariantClear( &varResult );
HRETURN( hr ); } //*** OnIsAlive( )
/////////////////////////////////////////////////////////////////////////////
//
// DWORD
// WINAPI
// CScriptResource::S_ThreadProc(
// LPVOID pParam
// )
//
/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI CScriptResource::S_ThreadProc( LPVOID pParam ) { MSG msg; HRESULT hr; DWORD dw; BOOL b;
CScriptResource * pscript = reinterpret_cast< CScriptResource * >( pParam );
Assert( pscript != NULL );
//
// Initialize COM.
//
hr = THR( CoInitializeEx( NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE ) ); if ( FAILED( hr ) ) goto Error;
for( ;; ) // ever
{ //
// Indicate that we are ready to do something.
//
b = SetEvent( pscript->m_hEventDone ); if ( !b ) goto Win32Error;
//
// Wait for someone to need something.
//
dw = WaitForSingleObject( pscript->m_hEventWait, INFINITE ); if ( dw != WAIT_OBJECT_0 ) { hr = HRESULT_FROM_WIN32( dw ); goto Error; }
//
// Reset the event.
//
b = ResetEvent( pscript->m_hEventWait ); if ( !b ) goto Win32Error;
//
// Do what they ask.
//
switch ( pscript->m_msg ) { case msgOPEN: pscript->m_hr = THR( pscript->OnOpen( ) ); break;
case msgCLOSE: pscript->m_hr = THR( pscript->OnClose( ) ); break;
case msgONLINE: pscript->m_hr = THR( pscript->OnOnline( ) ); break;
case msgOFFLINE: pscript->m_hr = THR( pscript->OnOffline( ) ); break;
case msgTERMINATE: pscript->m_hr = THR( pscript->OnTerminate( ) ); break;
case msgLOOKSALIVE: pscript->m_hr = STHR( pscript->OnLooksAlive( ) ); break;
case msgISALIVE: pscript->m_hr = STHR( pscript->OnIsAlive( ) ); break;
case msgDIE: //
// This means the resource is being released.
//
goto Cleanup; }
} // spin forever
Cleanup: CoUninitialize( ); return hr;
Error: pscript->LogError( hr ); goto Cleanup;
Win32Error: hr = HRESULT_FROM_WIN32( GetLastError( ) ); goto Error; } //*** S_ThreadProc( )
//////////////////////////////////////////////////////////////////////////////
//
// DWORD
// CScriptResource::MakeScriptEngineAssociation( pszScriptFileName )
//
// Description:
// Takes the filename and splits off the extension then queries
// the registry to obtain the association and finally queries the
// ScriptingEngine key under that association and allocates and
// returns a buffer containing the engine name. This engine name
// is suitable for input into CLSIDFromProgID.
//
// Arguments:
// pszScriptFileName - Pointer to null terminated script file name (full path with environment expanded).
//
// Return Values:
// NULL - Failure to read engine for this key, consult GetLastError() for details.
// Valid pointer to string buffer containing engine prog id.
//
//////////////////////////////////////////////////////////////////////////////
#define SCRIPTENGINE_KEY_STRING L"\\ScriptEngine"
LPWSTR CScriptResource::MakeScriptEngineAssociation( IN LPCWSTR pszScriptFileName ) { LPWSTR pszAssociation = NULL; LPWSTR pszEngineName = NULL; LONG lRegStatus = ERROR_SUCCESS; HKEY hKey = NULL; WCHAR szExtension[_MAX_EXT]; DWORD dwType, cbAssociationSize, cbEngineNameSize, dwNumChars;
//
// First split the path to get the extension.
//
_wsplitpath (pszScriptFileName, NULL, NULL, NULL, szExtension); if (szExtension[0] == L'\0') { SetLastError (ERROR_FILE_NOT_FOUND); goto Cleanup; }
//
// Pre-parse to patch up .scr association!
//
if (_wcsicmp (szExtension, L".scr") == 0) { LPWSTR pszSCREngine=NULL; pszSCREngine = (LPWSTR) TraceAlloc( GPTR, sizeof( L"VBScript" ) ); if ( pszSCREngine == NULL ) goto ErrorOutOfMemory; else { wcscpy (pszSCREngine, L"VBScript"); return pszSCREngine; } }
//
// If the pre-parse didn't get it then go to the registry to do
// the right thing.
//
lRegStatus = RegOpenKeyExW( HKEY_CLASSES_ROOT, // handle to open key
szExtension, // subkey name
0, // reserved
KEY_READ, // security access desired.
&hKey); // key handle returned
if (lRegStatus != ERROR_SUCCESS) goto Error; //
// Query the value to get the size of the buffer to allocate.
// NB cbSize contains the size including the '\0'
//
lRegStatus = RegQueryValueExW( hKey, // handle to key
NULL, // value name
0, // reserved
&dwType, // type buffer
NULL, // data buffer
&cbAssociationSize); // size of data buffer
if ( lRegStatus != ERROR_SUCCESS ) goto Error; if ( dwType != REG_SZ ) goto ErrorBadType;
dwNumChars = cbAssociationSize / sizeof (WCHAR); pszAssociation = (LPWSTR) TraceAlloc( GPTR, cbAssociationSize + sizeof (SCRIPTENGINE_KEY_STRING) ); if ( pszAssociation == NULL ) goto ErrorOutOfMemory;
// Get the value for real.
//
lRegStatus = RegQueryValueExW( hKey, // handle to key
NULL, // value name
0, // reserved
&dwType, // type buffer
(LPBYTE) pszAssociation, // data buffer
&cbAssociationSize ); // size of data buffer
if ( lRegStatus != ERROR_SUCCESS ) goto Error; if ( dwType != REG_SZ ) goto ErrorBadType; lRegStatus = RegCloseKey( hKey ); if ( lRegStatus != ERROR_SUCCESS ) goto Error; hKey = NULL;
//
// Take the data and make a key with \ScriptEngine on the end. If
// we find this then we can use the file.
//
swprintf( &pszAssociation[ dwNumChars - 1 ], SCRIPTENGINE_KEY_STRING ); pszAssociation[ dwNumChars + (sizeof( SCRIPTENGINE_KEY_STRING ) / sizeof ( WCHAR ) ) - 1 ] = L'\0'; lRegStatus = RegOpenKeyExW( HKEY_CLASSES_ROOT, // handle to open key
pszAssociation, // subkey name
0, // reserved
KEY_READ, // security access
&hKey ); // key handle
lRegStatus = RegQueryValueExW( hKey, // handle to key
NULL, // value name
0, // reserved
&dwType, // type buffer
NULL, // data buffer
&cbEngineNameSize); // size of data buffer
if ( lRegStatus != ERROR_SUCCESS ) goto Error; if ( dwType != REG_SZ ) goto ErrorBadType;
dwNumChars = cbEngineNameSize / sizeof (WCHAR); pszEngineName = (LPWSTR) TraceAlloc( GPTR, cbEngineNameSize ); if ( NULL == pszEngineName ) { goto ErrorOutOfMemory; } pszEngineName[ dwNumChars - 1 ] = '\0'; //
// Get the value for real.
//
lRegStatus = RegQueryValueExW( hKey, // handle to key
NULL, // value name
0, // reserved
&dwType, // type buffer
(LPBYTE) pszEngineName, // data buffer
&cbEngineNameSize); // size of data buffer
if ( lRegStatus != ERROR_SUCCESS ) goto Error; if ( dwType != REG_SZ ) goto ErrorBadType; lRegStatus = RegCloseKey( hKey ); if ( lRegStatus != ERROR_SUCCESS ) goto Error; hKey = NULL; goto Cleanup;
Error: SetLastError (lRegStatus); goto ErrorCleanup;
ErrorBadType: SetLastError (ERROR_FILE_NOT_FOUND); goto ErrorCleanup;
ErrorOutOfMemory: SetLastError (ERROR_NOT_ENOUGH_MEMORY); goto ErrorCleanup;
ErrorCleanup: if (pszEngineName) { TraceFree (pszEngineName); pszEngineName = NULL; } Cleanup: if (pszAssociation) TraceFree (pszAssociation); if (hKey) (void) RegCloseKey (hKey);
return pszEngineName; } #undef SCRIPTENGINE_KEY_STRING
//////////////////////////////////////////////////////////////////////////////
//
// HRESULT
// CScriptResource::DoConnect( szScriptFilePath )
//
// Description:
// Connects to the script engine associated with the script passed in.
//
// Arguments:
// pszScriptFileName - Pointer to null terminated script file name (full path with environment expanded).
//
// Return Values:
// S_OK - connected OK.
// Failure status - local cleanup performed.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CScriptResource::DoConnect( IN LPWSTR szScriptFilePath ) { HRESULT hr = S_OK; DWORD cbSize; DWORD dwErr; CLSID clsidScriptEngine;
CActiveScriptSite * psite;
//
// Create the scripting site.
//
psite = new CActiveScriptSite( m_hResource, ClusResLogEvent, m_hkeyParams, m_pszName ); if ( psite == NULL ) goto OutOfMemory;
hr = THR( psite->QueryInterface( IID_IActiveScriptSite, reinterpret_cast<void**>( &m_pass ) ) ); psite->Release( ); // release promptly
if ( FAILED( hr ) ) goto Error;
//
// Find the Active Engine.
//
if (szScriptFilePath == NULL) { (ClusResLogEvent)( m_hResource, LOG_INFORMATION, L"DoConnect: Default to VBScript\n");
hr = THR( CLSIDFromProgID( L"VBScript", &clsidScriptEngine ) ); if ( FAILED( hr ) ) goto Error; } else { (ClusResLogEvent)( m_hResource, LOG_INFORMATION, L"DoConnect: Got path: %1\n", szScriptFilePath);
//
// Find the program associated with the extension.
//
if ( m_pszScriptEngine != NULL ) { TraceFree( m_pszScriptEngine ); } m_pszScriptEngine = MakeScriptEngineAssociation( szScriptFilePath ); if ( m_pszScriptEngine == NULL) { (ClusResLogEvent)( m_hResource, LOG_ERROR, L"Error getting engine\n"); hr = HRESULT_FROM_WIN32( GetLastError( ) ); goto Error; }
(ClusResLogEvent)( m_hResource, LOG_ERROR, L"Got engine %1\n", m_pszScriptEngine);
hr = THR( CLSIDFromProgID( m_pszScriptEngine, &clsidScriptEngine ) ); if ( FAILED( hr ) ) { (ClusResLogEvent)( m_hResource, LOG_ERROR, L"Error getting prog ID\n"); goto Error; } } //
// Create an instance of it.
//
TraceDo( hr = THR( CoCreateInstance( clsidScriptEngine, NULL, CLSCTX_SERVER, IID_IActiveScriptParse, reinterpret_cast<void**>( &m_pasp ) ) ) ); if ( FAILED( hr ) ) { (ClusResLogEvent)( m_hResource, LOG_ERROR, L"DoConnect: Failed to create instance of CLSID\n"); goto Error; } m_pasp = TraceInterface( L"Active Script Engine", IActiveScriptParse, m_pasp, 1 );
TraceDo( hr = THR( m_pasp->QueryInterface( IID_IActiveScript, (void**) &m_pas ) ) ); if ( FAILED( hr ) ) goto Error; m_pas = TraceInterface( L"Active Script Engine", IActiveScript, m_pas, 1 );
//
// Initialize it.
//
TraceDo( hr = THR( m_pasp->InitNew( ) ) ); if ( FAILED( hr ) ) { (ClusResLogEvent)( m_hResource, LOG_ERROR, L"DoConnect: Failed to InitNew\n"); goto Error; }
#if defined(DEBUG)
//
// Set our site. We'll give out a new tracking interface to track this separately.
//
{ IActiveScriptSite * psite; hr = THR( m_pass->TypeSafeQI( IActiveScriptSite, &psite ) ); Assert( hr == S_OK );
TraceDo( hr = THR( m_pas->SetScriptSite( psite ) ) ); psite->Release( ); // release promptly
if ( FAILED( hr ) ) goto Error; } #else
TraceDo( hr = THR( m_pas->SetScriptSite( m_pass ) ) ); if ( FAILED( hr ) ) { (ClusResLogEvent)( m_hResource, LOG_ERROR, L"DoConnect: Failed to SetScriptSite\n"); goto Error; } #endif
//
// Add Document to the global members.
//
TraceDo( hr = THR( m_pas->AddNamedItem( L"Resource", SCRIPTITEM_ISVISIBLE ) ) ); if ( FAILED( hr ) ) goto Error;
//
// Connect the script.
//
TraceDo( hr = THR( m_pas->SetScriptState( SCRIPTSTATE_CONNECTED ) ) ); if ( FAILED( hr ) ) { (ClusResLogEvent)( m_hResource, LOG_ERROR, L"DoConnect: Failed to SetScriptState\n"); goto Error; } //
// Get the dispatch inteface to the script.
//
TraceDo( hr = THR( m_pas->GetScriptDispatch( NULL, &m_pidm ) ) ); if ( FAILED( hr) ) { (ClusResLogEvent)( m_hResource, LOG_ERROR, L"DoConnect: Failed to GetScriptDispatch\n"); goto Error; } m_pidm = TraceInterface( L"Active Script", IDispatch, m_pidm, 1 );
hr = S_OK;
Cleanup: HRETURN( hr );
Error: LogError( hr ); goto Cleanup;
OutOfMemory: hr = E_OUTOFMEMORY; goto Cleanup; }
//////////////////////////////////////////////////////////////////////////////
//
// void
// CScriptResource::DoDisconnect( )
//
// Description:
// Disconnects from any currently connected script engine.
//
// Arguments:
// none.
//
// Return Values:
// none.
//
//////////////////////////////////////////////////////////////////////////////
void CScriptResource::DoDisconnect( ) { //
// Cleanup the scripting engine.
//
if ( m_pszScriptFilePath != NULL ) { LocalFree( m_pszScriptFilePath ); m_pszScriptFilePath = NULL; } // if: m_pszScriptFilePath
if ( m_pszScriptEngine != NULL ) { TraceFree( m_pszScriptEngine ); m_pszScriptEngine = NULL; } // if: m_pszScriptEngine
if ( m_pidm != NULL ) { TraceDo( m_pidm->Release( ) ); m_pidm = NULL; } // if: m_pidm
if ( m_pasp != NULL ) { TraceDo( m_pasp->Release( ) ); m_pasp = NULL; } // if: m_pasp
if ( m_pas != NULL ) { TraceDo( m_pas->Close( ) ); TraceDo( m_pas->Release( ) ); m_pas = NULL; } // if: m_pas
if ( m_pass != NULL ) { TraceDo( m_pass->Release( ) ); m_pass = NULL; } // if: m_pass
}
|