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.
1433 lines
32 KiB
1433 lines
32 KiB
/*++
|
|
|
|
Copyright (c) 1997-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ptreg.cpp
|
|
|
|
Abstract:
|
|
|
|
Implementation of Plug-Terminal Registration classes.
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
#include "PTReg.h"
|
|
#include "manager.h"
|
|
#include <atlwin.h>
|
|
#include <atlwin.cpp>
|
|
|
|
|
|
//
|
|
// CPlugTerminal class implementation
|
|
// Create free thread marshaler
|
|
//
|
|
|
|
HRESULT CPlugTerminal::FinalConstruct(void)
|
|
{
|
|
LOG((MSP_TRACE, "CPlugTerminal::FinalConstruct - enter"));
|
|
|
|
HRESULT hr = CoCreateFreeThreadedMarshaler( GetControllingUnknown(),
|
|
& m_pFTM );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::FinalConstruct - "
|
|
"create FTM returned 0x%08x; exit", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::FinalConstruct - exit S_OK"));
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
//
|
|
// CPlugTerminal class implementation
|
|
// --- ITPTRegTerminal interface ---
|
|
//
|
|
|
|
STDMETHODIMP CPlugTerminal::get_Name(
|
|
/*[out, retval]*/ BSTR* pName
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::get_Name - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if( TM_IsBadWritePtr( pName, sizeof(BSTR)) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_Name exit -"
|
|
"pName invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Validates the name
|
|
//
|
|
|
|
if( IsBadStringPtr( m_Terminal.m_bstrName, (UINT)-1) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_Name exit -"
|
|
"m_bstrName invalid, returns E_UNEXPECTED"));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// Return the name
|
|
//
|
|
|
|
*pName = SysAllocString( m_Terminal.m_bstrName );
|
|
|
|
//
|
|
// Validates SysAllocString
|
|
//
|
|
|
|
if( *pName == NULL )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_Name exit -"
|
|
"SysAllocString failed, returns E_OUTOFMEMORY"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::get_Name - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::put_Name(
|
|
/*[in]*/ BSTR bstrName
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::put_Name - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if(IsBadStringPtr( bstrName, (UINT)-1) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::put_Name exit -"
|
|
"bstrName invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Clean-up the old name
|
|
//
|
|
|
|
if(!IsBadStringPtr( m_Terminal.m_bstrName, (UINT)-1) )
|
|
{
|
|
SysFreeString( m_Terminal.m_bstrName );
|
|
m_Terminal.m_bstrName = NULL;
|
|
}
|
|
|
|
//
|
|
// Set the new name
|
|
//
|
|
|
|
m_Terminal.m_bstrName = SysAllocString( bstrName );
|
|
|
|
//
|
|
// Validates SysAllocString
|
|
//
|
|
|
|
if( NULL == m_Terminal.m_bstrName )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::put_Name exit -"
|
|
"SysAllocString failed, returns E_OUTOFMEMORY"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::put_Name - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::get_Company(
|
|
/*[out, retval]*/ BSTR* pCompany
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::get_Company - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if( TM_IsBadWritePtr( pCompany, sizeof(BSTR)) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_Company exit -"
|
|
"pCompany invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Validates the company
|
|
//
|
|
|
|
if( IsBadStringPtr( m_Terminal.m_bstrCompany, (UINT)-1) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_Company exit -"
|
|
"m_bstrCompany invalid, returns E_UNEXPECTED"));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// Return the Company
|
|
//
|
|
|
|
*pCompany = SysAllocString( m_Terminal.m_bstrCompany );
|
|
|
|
//
|
|
// Validates SysAllocString
|
|
//
|
|
|
|
if( *pCompany == NULL )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_Company exit -"
|
|
"SysAllocString failed, returns E_OUTOFMEMORY"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::get_Company - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::put_Company(
|
|
/*[in]*/ BSTR bstrCompany
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::put_Company - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if(IsBadStringPtr( bstrCompany, (UINT)-1) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::put_Company exit -"
|
|
"bstrCompany invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Clean-up the old company
|
|
//
|
|
|
|
if(!IsBadStringPtr( m_Terminal.m_bstrCompany, (UINT)-1) )
|
|
{
|
|
SysFreeString( m_Terminal.m_bstrCompany );
|
|
m_Terminal.m_bstrCompany = NULL;
|
|
}
|
|
|
|
//
|
|
// Set the new company
|
|
//
|
|
|
|
m_Terminal.m_bstrCompany = SysAllocString( bstrCompany );
|
|
|
|
//
|
|
// Validates SysAllocString
|
|
//
|
|
|
|
if( NULL == m_Terminal.m_bstrCompany )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::put_Company exit -"
|
|
"SysAllocString failed, returns E_OUTOFMEMORY"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::put_Company - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::get_Version(
|
|
/*[out, retval]*/ BSTR* pVersion
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::get_Version - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if( TM_IsBadWritePtr( pVersion, sizeof(BSTR)) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_Version exit -"
|
|
"pVersion invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Validates the version
|
|
//
|
|
|
|
if( IsBadStringPtr( m_Terminal.m_bstrVersion, (UINT)-1) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_Version exit -"
|
|
"m_bstrVersion invalid, returns E_UNEXPECTED"));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// Return the Version
|
|
//
|
|
|
|
*pVersion = SysAllocString( m_Terminal.m_bstrVersion );
|
|
|
|
//
|
|
// Validates SysAllocString
|
|
//
|
|
|
|
if( *pVersion == NULL )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_Version exit -"
|
|
"SysAllocString failed, returns E_OUTOFMEMORY"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::get_Version - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::put_Version(
|
|
/*[in]*/ BSTR bstrVersion
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::put_Version - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if(IsBadStringPtr( bstrVersion, (UINT)-1) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::put_Version exit -"
|
|
"bstrVersion invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Clean-up the old version
|
|
//
|
|
|
|
if(!IsBadStringPtr( m_Terminal.m_bstrVersion, (UINT)-1) )
|
|
{
|
|
SysFreeString( m_Terminal.m_bstrVersion );
|
|
m_Terminal.m_bstrVersion = NULL;
|
|
}
|
|
|
|
//
|
|
// Set the new Version
|
|
//
|
|
|
|
m_Terminal.m_bstrVersion = SysAllocString( bstrVersion );
|
|
|
|
//
|
|
// Validates SysAllocString
|
|
//
|
|
|
|
if( NULL == m_Terminal.m_bstrVersion )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::put_Version exit -"
|
|
"SysAllocString failed, returns E_OUTOFMEMORY"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::put_Version - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::get_TerminalClass(
|
|
/*[out, retval]*/ BSTR* pTerminalClass
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::get_TerminalClass - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if( TM_IsBadWritePtr( pTerminalClass, sizeof(BSTR)) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_TerminalClass exit -"
|
|
"pTerminalClass invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Return the TerminalClass
|
|
//
|
|
|
|
LPOLESTR lpszTerminalClass = NULL;
|
|
HRESULT hr = StringFromCLSID(
|
|
m_Terminal.m_clsidTerminalClass,
|
|
&lpszTerminalClass
|
|
);
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_TerminalClass exit -"
|
|
"StringFromCLSID failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
*pTerminalClass = SysAllocString( lpszTerminalClass );
|
|
|
|
// Clean-up
|
|
CoTaskMemFree( lpszTerminalClass );
|
|
|
|
//
|
|
// Validates SysAllocString
|
|
//
|
|
|
|
if( *pTerminalClass == NULL )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_TerminalClass exit -"
|
|
"SysAllocString failed, returns E_OUTOFMEMORY"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::get_TerminalClass - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::put_TerminalClass(
|
|
/*[in]*/ BSTR bstrTerminalClass
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::put_TerminalClass - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if(IsBadStringPtr( bstrTerminalClass, (UINT)-1) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::put_TerminalClass exit -"
|
|
"bstrTerminalClass invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Is a real CLSID?
|
|
//
|
|
|
|
CLSID clsidTerminalClass;
|
|
HRESULT hr = CLSIDFromString(bstrTerminalClass, &clsidTerminalClass);
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::put_TerminalClass exit -"
|
|
"bstrTerminalClass is not a CLSID, returns E_INVALIDARG"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
//
|
|
// Clean-up the old TerminalClass
|
|
//
|
|
|
|
m_Terminal.m_clsidTerminalClass = clsidTerminalClass;
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::put_TerminalClass - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::get_CLSID(
|
|
/*[out, retval]*/ BSTR* pCLSID
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::get_CLSID - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if( TM_IsBadWritePtr( pCLSID, sizeof(BSTR)) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_CLSID exit -"
|
|
"pCLSID invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
if( m_Terminal.m_clsidCOM == CLSID_NULL )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_CLSID exit -"
|
|
"clsid is NULL, returns E_UNEXPECTED"));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// Return the CLSID
|
|
//
|
|
|
|
LPOLESTR lpszCLSID = NULL;
|
|
HRESULT hr = StringFromCLSID( m_Terminal.m_clsidCOM, &lpszCLSID);
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_CLSID exit -"
|
|
"StringFromCLSID failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
*pCLSID = SysAllocString( lpszCLSID );
|
|
|
|
// Clean-up
|
|
CoTaskMemFree( lpszCLSID );
|
|
|
|
//
|
|
// Validates SysAllocString
|
|
//
|
|
|
|
if( *pCLSID == NULL )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_CLSID exit -"
|
|
"SysAllocString failed, returns E_OUTOFMEMORY"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::get_CLSID - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::put_CLSID(
|
|
/*[in]*/ BSTR bstrCLSID
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::put_CLSID - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if(IsBadStringPtr( bstrCLSID, (UINT)-1) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::put_CLSID exit -"
|
|
"bstrCLSID invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Is a real CLSID?
|
|
//
|
|
|
|
CLSID clsidCOM;
|
|
HRESULT hr = CLSIDFromString(bstrCLSID, &clsidCOM);
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::put_CLSID exit -"
|
|
"bstrCLSID is not a CLSID, returns E_INVALIDARG"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
//
|
|
// Clean-up the old CLSID
|
|
//
|
|
|
|
m_Terminal.m_clsidCOM = clsidCOM;
|
|
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::put_CLSID - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::get_Direction(
|
|
/*[out, retval]*/ TMGR_DIRECTION* pDirection
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::get_Direction - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if( TM_IsBadWritePtr( pDirection, sizeof(long)) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_Direction exit -"
|
|
"pDirections invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Return the Direction
|
|
//
|
|
|
|
*pDirection = (TMGR_DIRECTION)m_Terminal.m_dwDirections;
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::get_Direction - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::put_Direction(
|
|
/*[in]*/ TMGR_DIRECTION nDirection
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::put_Direction - enter"));
|
|
|
|
if( nDirection == 0 )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::put_Direction exit -"
|
|
"nDirections invalid, returns E_INVALIDARG"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if( (nDirection & (
|
|
((long)TMGR_TD_RENDER) |
|
|
((long)TMGR_TD_CAPTURE))) != nDirection )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::put_Direction exit -"
|
|
"nDirections invalid, returns E_INVALIDARG"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
//
|
|
// Set the new direction
|
|
//
|
|
|
|
m_Terminal.m_dwDirections = nDirection;
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::put_Direction - exit S_OK"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::get_MediaTypes(
|
|
/*[out, retval]*/ long* pMediaTypes
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::get_MediaTypes - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if( TM_IsBadWritePtr( pMediaTypes, sizeof(long)) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::get_MediaTypes exit -"
|
|
"pMediaTypes invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Return the MediaTypes
|
|
//
|
|
|
|
*pMediaTypes = (long)m_Terminal.m_dwMediaTypes;
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::get_MediaTypes - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::put_MediaTypes(
|
|
/*[in]*/ long nMediaTypes
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::put_MediaTypes - enter"));
|
|
|
|
if( nMediaTypes == 0)
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::put_MediaTypes exit -"
|
|
"nMediaTypes invalid, returns E_INVALIDARG"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if( (nMediaTypes & (
|
|
((long)TAPIMEDIATYPE_AUDIO) |
|
|
((long)TAPIMEDIATYPE_VIDEO) |
|
|
((long)TAPIMEDIATYPE_MULTITRACK))) != nMediaTypes )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::put_MediaTypes exit -"
|
|
"nMediaTypes invalid, returns E_INVALIDARG"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Set the new direction
|
|
//
|
|
|
|
m_Terminal.m_dwMediaTypes = nMediaTypes;
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::put_MediaTypes - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::Add(
|
|
/*[in]*/ BSTR bstrSuperclass
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::Add - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if(IsBadStringPtr( bstrSuperclass, (UINT)-1) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::Add exit -"
|
|
"bstrTermClassCLSID invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Is a real CLSID
|
|
//
|
|
CLSID clsidSuperclass = CLSID_NULL;
|
|
HRESULT hr = E_FAIL;
|
|
hr = CLSIDFromString( bstrSuperclass, &clsidSuperclass);
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::Add exit -"
|
|
"bstrTermClassCLSID is not a CLSID, returns E_INVALIDARG"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Add
|
|
//
|
|
|
|
hr = m_Terminal.Add( clsidSuperclass );
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::Add - exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::Delete(
|
|
/*[in]*/ BSTR bstrSuperclass
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::Delete - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if(IsBadStringPtr( bstrSuperclass, (UINT)-1) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::Delete exit -"
|
|
"bstrTermClassCLSID invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Is a real CLSID
|
|
//
|
|
CLSID clsidSuperclass = CLSID_NULL;
|
|
HRESULT hr = E_FAIL;
|
|
hr = CLSIDFromString( bstrSuperclass, &clsidSuperclass);
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::Delete exit -"
|
|
"bstrTermClassCLSID is not a CLSID, returns E_INVALIDARG"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Delete
|
|
//
|
|
|
|
hr = m_Terminal.Delete( clsidSuperclass );
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::Delete - exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminal::GetTerminalClassInfo(
|
|
/*[in]*/ BSTR bstrSuperclass
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::GetTerminal - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if(IsBadStringPtr( bstrSuperclass, (UINT)-1) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::GetTerminal exit -"
|
|
"bstrTermClassCLSID invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Is a real CLSID
|
|
//
|
|
CLSID clsidSuperclass = CLSID_NULL;
|
|
HRESULT hr = E_FAIL;
|
|
hr = CLSIDFromString( bstrSuperclass, &clsidSuperclass);
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminal::GetTerminal exit -"
|
|
"bstrTermClassCLSID is not a CLSID, returns E_INVALIDARG"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
//
|
|
// Get terminal
|
|
//
|
|
|
|
hr = m_Terminal.Get( clsidSuperclass );
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminal::GetTerminal - exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// CPlugTerminalSuperlass class implementation
|
|
// Create free thread marshaler
|
|
//
|
|
|
|
HRESULT CPlugTerminalSuperclass::FinalConstruct(void)
|
|
{
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::FinalConstruct - enter"));
|
|
|
|
HRESULT hr = CoCreateFreeThreadedMarshaler( GetControllingUnknown(),
|
|
& m_pFTM );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::FinalConstruct - "
|
|
"create FTM returned 0x%08x; exit", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::FinalConstruct - exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// CPlugTerminalSuperlass class implementation
|
|
// --- ITPTRegTerminalClass interface ---
|
|
//
|
|
|
|
STDMETHODIMP CPlugTerminalSuperclass::get_Name(
|
|
/*[out, retval]*/ BSTR* pName
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::get_Name - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if( TM_IsBadWritePtr( pName, sizeof(BSTR)) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::get_Name exit -"
|
|
"pName invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Validate internal name
|
|
//
|
|
|
|
if( IsBadStringPtr( m_Superclass.m_bstrName, (UINT)-1) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::get_Name exit -"
|
|
"bstrName invalid, returns E_UNEXPECTED"));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// Returns name
|
|
//
|
|
|
|
*pName = SysAllocString( m_Superclass.m_bstrName);
|
|
|
|
//
|
|
// Validate SysAllocString
|
|
//
|
|
|
|
if( *pName == NULL )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::get_Name exit -"
|
|
"SysAllocString failed, returns E_OUTOFMEMORY"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::get_Name - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminalSuperclass::put_Name(
|
|
/*[in]*/ BSTR bstrName
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::put_Name - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if(IsBadStringPtr( bstrName, (UINT)-1) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::put_Name exit -"
|
|
"bstrName invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Clean-up the old name
|
|
//
|
|
|
|
if(!IsBadStringPtr( m_Superclass.m_bstrName, (UINT)-1) )
|
|
{
|
|
SysFreeString( m_Superclass.m_bstrName );
|
|
m_Superclass.m_bstrName = NULL;
|
|
}
|
|
|
|
//
|
|
// Set the new name
|
|
//
|
|
|
|
m_Superclass.m_bstrName = SysAllocString( bstrName );
|
|
|
|
//
|
|
// Validates the sysAllocString
|
|
//
|
|
|
|
if( NULL == m_Superclass.m_bstrName )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::put_Name exit -"
|
|
"SysAllocString failed, returns E_OUTOFMEMORY"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::put_Name - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminalSuperclass::get_CLSID(
|
|
/*[out, retval]*/ BSTR* pCLSIDClass
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::get_CLSIDClass - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if( TM_IsBadWritePtr( pCLSIDClass, sizeof(BSTR)) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::get_CLSIDClass exit -"
|
|
"pCLSIDClass invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Returns CLSID
|
|
//
|
|
LPOLESTR lpszSuperclassCLSID = NULL;
|
|
HRESULT hr = StringFromCLSID( m_Superclass.m_clsidSuperclass, &lpszSuperclassCLSID);
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::get_CLSIDClass exit -"
|
|
"StringFromClSID failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
*pCLSIDClass = SysAllocString( lpszSuperclassCLSID);
|
|
|
|
// Clean-up
|
|
CoTaskMemFree( lpszSuperclassCLSID );
|
|
|
|
//
|
|
// Validates SysAllocString
|
|
//
|
|
|
|
if( *pCLSIDClass == NULL )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::get_CLSIDClass exit -"
|
|
"SysAllocString failed, returns E_OUTOFMEMORY"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::get_CLSIDClass - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminalSuperclass::put_CLSID(
|
|
/*[in]*/ BSTR bstrCLSIDClass
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::put_CLSIDClass - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if(IsBadStringPtr( bstrCLSIDClass, (UINT)-1) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::put_CLSIDClass exit -"
|
|
"bstrCLSIDClass invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Is a real CLSID?
|
|
//
|
|
|
|
CLSID clsidSuperclassClSID;
|
|
HRESULT hr = CLSIDFromString(bstrCLSIDClass, &clsidSuperclassClSID);
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::put_CLSIDClass exit -"
|
|
"bstrCLSIDClass is not a CLSID, returns E_INVALIDARG"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Clean-up the old CLSID
|
|
//
|
|
|
|
m_Superclass.m_clsidSuperclass = clsidSuperclassClSID;
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::put_CLSIDClasse - exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminalSuperclass::Add(
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::Add - enter"));
|
|
|
|
//
|
|
// Add terminal class
|
|
//
|
|
|
|
HRESULT hr = E_FAIL;
|
|
hr = m_Superclass.Add();
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::Add - exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminalSuperclass::Delete(
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::Deletee - enter"));
|
|
|
|
//
|
|
// Delete terminalc class
|
|
//
|
|
|
|
HRESULT hr = E_FAIL;
|
|
hr = m_Superclass.Delete();
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::Delete - exit 0x%08x",hr));
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminalSuperclass::GetTerminalSuperclassInfo(
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::GetTerminalSuperclassInfo - enter"));
|
|
|
|
//
|
|
// Get terminal class from registry
|
|
//
|
|
|
|
HRESULT hr = E_FAIL;
|
|
hr = m_Superclass.Get();
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::GetTerminalSuperclassInfo - exit 0x%08x",hr));
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminalSuperclass::get_TerminalClasses(
|
|
/*[out, retval]*/ VARIANT* pVarTerminals
|
|
)
|
|
{
|
|
//
|
|
// Critical section
|
|
//
|
|
|
|
CLock lock(m_CritSect);
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::get_TerminalClasses - enter"));
|
|
|
|
//
|
|
// Validates argument
|
|
//
|
|
|
|
if( TM_IsBadWritePtr( pVarTerminals, sizeof(VARIANT)) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::get_TerminalClasses exit -"
|
|
"pTerminals invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// reset the output argument
|
|
//
|
|
|
|
pVarTerminals->parray = NULL;
|
|
pVarTerminals->vt = VT_EMPTY;
|
|
|
|
//
|
|
// List the terminals
|
|
//
|
|
|
|
HRESULT hr = E_FAIL;
|
|
CLSID* pTerminals = NULL;
|
|
DWORD dwTerminals = 0;
|
|
|
|
hr = m_Superclass.ListTerminalClasses( 0,
|
|
&pTerminals,
|
|
&dwTerminals
|
|
);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::get_TerminalClasses exit -"
|
|
"ListTerminalClasses failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Create a safe array for the terminasl
|
|
//
|
|
|
|
SAFEARRAY* psaTerminals = NULL;
|
|
SAFEARRAYBOUND rgsabound;
|
|
rgsabound.lLbound = 1;
|
|
rgsabound.cElements = dwTerminals;
|
|
psaTerminals = SafeArrayCreate(
|
|
VT_BSTR,
|
|
1,
|
|
&rgsabound);
|
|
if( psaTerminals == NULL )
|
|
{
|
|
// Clean-up
|
|
delete[] pTerminals;
|
|
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::get_TerminalClasses exit -"
|
|
"SafeArrayCreate failed, returns E_OUTOFMEMORY"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Copies into the safe array the elements
|
|
//
|
|
|
|
for( DWORD dwTerminal = 0; dwTerminal < dwTerminals; dwTerminal++)
|
|
{
|
|
LPOLESTR lpszTerminalClass = NULL;
|
|
hr = StringFromCLSID( pTerminals[dwTerminal], &lpszTerminalClass);
|
|
if( FAILED(hr) )
|
|
{
|
|
// Clean-up
|
|
delete[] pTerminals;
|
|
SafeArrayDestroy( psaTerminals );
|
|
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::get_TerminalClasses exit -"
|
|
"StringFromCLSID failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
BSTR bstrTerminalClass = SysAllocString( lpszTerminalClass );
|
|
|
|
CoTaskMemFree( lpszTerminalClass );
|
|
|
|
if( bstrTerminalClass == NULL )
|
|
{
|
|
// Clean-up
|
|
delete[] pTerminals;
|
|
SafeArrayDestroy( psaTerminals );
|
|
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::get_TerminalClasses exit -"
|
|
"sysAloocString failed, returns E_OUTOFMEMORY"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Put the element into the array
|
|
long nIndex = (long)(dwTerminal+1);
|
|
hr = SafeArrayPutElement( psaTerminals, &nIndex, bstrTerminalClass );
|
|
if( FAILED(hr) )
|
|
{
|
|
// Clean-up
|
|
delete[] pTerminals;
|
|
SafeArrayDestroy( psaTerminals );
|
|
SysFreeString( bstrTerminalClass );
|
|
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::get_TerminalClasses exit -"
|
|
"SafeArrayPutElement failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
// Clean-up
|
|
delete[] pTerminals;
|
|
|
|
// Return values
|
|
pVarTerminals->parray = psaTerminals;
|
|
pVarTerminals->vt = VT_ARRAY | VT_BSTR;
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::get_TerminalClasses - exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CPlugTerminalSuperclass::EnumerateTerminalClasses(
|
|
OUT IEnumTerminalClass** ppTerminals
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::EnumerateTerminalClasses - enter"));
|
|
|
|
//
|
|
// Validate argument
|
|
//
|
|
if( TM_IsBadWritePtr( ppTerminals, sizeof(IEnumTerminalClass*)) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::EnumerateTerminalClasses exit -"
|
|
"ppTerminals invalid, returns E_POINTER"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
CLSID* pTerminals = NULL;
|
|
DWORD dwTerminals = 0;
|
|
|
|
HRESULT hr = m_Superclass.ListTerminalClasses( 0,
|
|
&pTerminals,
|
|
&dwTerminals
|
|
);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::EnumerateTerminalClasses exit -"
|
|
"ListTerminalClasses failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Create a buffer with exactly dwTerminals size
|
|
//
|
|
CLSID* pTerminalsCLSID = new CLSID[dwTerminals];
|
|
if( pTerminalsCLSID == NULL )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::EnumerateTerminalClasses exit -"
|
|
"new operator failed, returns E_OUTOFMEMORY"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Copies into the new buffer
|
|
//
|
|
memcpy( pTerminalsCLSID, pTerminals, sizeof(CLSID)*dwTerminals);
|
|
|
|
//
|
|
// Delete the old buffer
|
|
//
|
|
delete[] pTerminals;
|
|
|
|
//
|
|
// Create the enumerator
|
|
//
|
|
typedef CSafeComEnum<IEnumTerminalClass,
|
|
&IID_IEnumTerminalClass,
|
|
GUID, _Copy<GUID> > CEnumerator;
|
|
|
|
CComObject<CEnumerator> *pEnum = NULL;
|
|
hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
|
|
if( FAILED(hr) )
|
|
{
|
|
delete[] pTerminalsCLSID;
|
|
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::EnumerateTerminalClasses exit -"
|
|
"CreateInstance failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Initialize enumerator
|
|
//
|
|
hr = pEnum->Init(pTerminalsCLSID,
|
|
pTerminalsCLSID+dwTerminals,
|
|
NULL,
|
|
AtlFlagTakeOwnership);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
delete pEnum;
|
|
delete[] pTerminalsCLSID;
|
|
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::EnumerateTerminalClasses exit -"
|
|
"Init failed, returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Query for the desired interface.
|
|
//
|
|
|
|
hr = pEnum->_InternalQueryInterface(
|
|
IID_IEnumTerminalClass,
|
|
(void**) ppTerminals
|
|
);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CPlugTerminalSuperclass::EnumerateTerminalClasses exit - "
|
|
"can't get enumerator interface - exit 0x%08x", hr));
|
|
|
|
delete pEnum;
|
|
delete[] pTerminalsCLSID;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
LOG((MSP_TRACE, "CPlugTerminalSuperclass::EnumerateTerminalClasses - exit S_OK"));
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// eof
|