Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

2035 lines
51 KiB

//////////////////////////////////////////////////////////////////////////////
//
// 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
}