WindowsXP-SP1/windows/oleacc/oleacc/propmgr_impl.cpp
2020-09-30 16:53:49 +02:00

1462 lines
36 KiB
C++

// Copyright (c) 2000-2000 Microsoft Corporation
// --------------------------------------------------------------------------
//
// PropMgr_Impl
//
// Property manager server class
//
// --------------------------------------------------------------------------
#include "oleacc_p.h"
#include <atlbase.h>
extern CComModule _Module;
#include <atlcom.h>
#include "PropMgr_Util.h"
#include "PropMgr_Impl.h"
#include "PropMgr_Mem.h"
#pragma warning(push, 3)
#pragma warning(disable: 4530)
#include <map>
#include <vector>
#pragma warning(pop)
#include "debug.h"
/*
Format of item record:
* size prefix
* 'Properties present' bitmask
Indicates that the property is present for this key
* 'Property is a variant' bitmask
For present properties, indicates whether the property is a VARIANT
versus an object reference.
* 'Property has container scope' bitmask
Indicates that the property applies to this key, and to all that element's
simple children.
* Property data: For each property which is present (see 'property present'
bitmask), there is:
either
* a serialized VARIANT
or
* a serialized/marshalled callback object reference (IAccPropServer)
- depending on whether the 'property is variant' bitmask is set for this property.
Variants are serialized as a leading SHORT indicating the type (VT_???), followed by:
DWORD for I4s,
DWORD length followed by unicode chars for BSTR
A marshalled callback reference is serialized as:
DWORD for length of marshalled data,
BYTEs of the marshalled data.
*/
BOOL IsKeyAlive( const BYTE * pKeyData, DWORD dwKeyLen )
{
// For the moment, assume it uses either the HWND or HMENU naming scheme.
// (Later on, if we extend this to allow pluggable namespaces, we'd use something
// like IAccNamespace::IsKeyAlive() instead.)
HWND hwnd;
if( DecodeHwndKey( pKeyData, dwKeyLen, & hwnd, NULL, NULL ) )
{
return IsWindow( hwnd );
}
HMENU hmenu;
if( DecodeHmenuKey( pKeyData, dwKeyLen, NULL, & hmenu, NULL ) )
{
return IsMenu( hmenu );
}
Assert( FALSE );
return FALSE;
}
// This is a reference to a key (aka id string) - it does not own or contain
// the key.
//
// When used in the object map, (which contains {AccObjKeyRef, AccInfo*} pairs),
// m_pKeyData points to the key data in the corresponding AccInfo. This object
// and the corresponding AccInfo have identical lifetimes.
//
// In other cases - for example, when used as a value to look up in the map -
// m_pKeyData points to an already existing key string - possibly the id string
// specified by the caller of one of the IAccPropServer methods. In this usage,
// the AccObjKeyRef is really being used as a temporary adapter to allow the
// existing string to be used to look up a value in the map.
class AccObjKeyRef
{
const BYTE * m_pKeyData;
DWORD m_dwKeyLen;
// Disable default ctor
AccObjKeyRef();
public:
// copy ctor
AccObjKeyRef( const BYTE * pKeyData, DWORD dwKeyLen )
: m_pKeyData( pKeyData ),
m_dwKeyLen( dwKeyLen )
{
}
// use default member-wise assignment
// Comparisons - used in map lookup
bool operator < ( const AccObjKeyRef & x ) const
{
if( m_dwKeyLen != x.m_dwKeyLen )
return m_dwKeyLen < x.m_dwKeyLen;
return memcmp( m_pKeyData, x.m_pKeyData, m_dwKeyLen ) < 0;
}
bool operator == ( const AccObjKeyRef & x ) const
{
if( m_dwKeyLen != x.m_dwKeyLen )
return false;
return memcmp( m_pKeyData, x.m_pKeyData, m_dwKeyLen ) == 0;
}
bool operator != ( const AccObjKeyRef & x ) const
{
return ! operator == ( x );
}
};
struct AccInfo
{
private:
// disable copy ctor
AccInfo( const AccInfo & x );
private:
struct PropInfo
{
union {
VARIANT m_var;
struct
{
BYTE * m_pMarshalData;
DWORD m_dwMarshalDataLen;
} m_ServerInfo;
};
};
BYTE * m_pKeyData;
DWORD m_dwKeyLen;
DWORD m_fPropInUseBits;
DWORD m_fPropIsVariantBits; // 1-bit indicates the property is VARIANT - otherwise it's a IAccPropServer
DWORD m_fContainerScopeBits; // 1-bit indicates that the property is a IAccPropServer, and should also
// be used for the children of this node. (annoScope was CONTAINER).
PropInfo m_Props[ NUMPROPS ];
HWND m_hwndProp;
LPTSTR m_pKeyString;
BYTE * m_pBlob;
public:
AccInfo()
{
m_fPropInUseBits = 0;
m_fPropIsVariantBits = 0;
m_fContainerScopeBits = 0;
m_pKeyString = NULL;
m_hwndProp = NULL;
m_pBlob = NULL;
}
~AccInfo()
{
ClearBlob();
for( int i = 0 ; i < NUMPROPS ; i++ )
{
ClearProp( i );
}
delete [ ] m_pKeyData;
delete [ ] m_pKeyString;
}
BOOL Init( const BYTE * pKeyData, DWORD dwKeyLen, HWND hwndProp )
{
m_pKeyData = new BYTE [ dwKeyLen ];
if( ! m_pKeyData )
{
TraceError( TEXT("AccInfo::Init: new returned NULL") );
return FALSE;
}
memcpy( m_pKeyData, pKeyData, dwKeyLen );
m_dwKeyLen = dwKeyLen;
m_pKeyString = MakeKeyString( pKeyData, dwKeyLen );
m_hwndProp = hwndProp;
return TRUE;
}
const AccObjKeyRef GetKeyRef()
{
return AccObjKeyRef( m_pKeyData, m_dwKeyLen );
}
BOOL SetPropValue (
int iProp,
VARIANT * pvarValue )
{
ClearProp( iProp );
SetBit( & m_fPropIsVariantBits, iProp );
SetBit( & m_fPropInUseBits, iProp );
ClearBit( & m_fContainerScopeBits, iProp );
m_Props[ iProp ].m_var.vt = VT_EMPTY;
// We'll accept any type here. It's up to the caller of this to enforce
// any property-vs-type policies (eg. only allow I4's for ROLE, etc.)
VariantCopy( & m_Props[ iProp ].m_var, pvarValue );
return TRUE;
}
BOOL SetPropServer (
int iProp,
const BYTE * pMarshalData,
int dwMarshalDataLen,
AnnoScope annoScope )
{
if( dwMarshalDataLen == 0 )
{
TraceError( TEXT("AccInfo::SetPropServer: dwMarshalDataLen param = 0") );
return FALSE;
}
BYTE * pCopyData = new BYTE [ dwMarshalDataLen ];
if( ! pCopyData )
{
TraceError( TEXT("AccInfo::SetPropServer: new returned NULL") );
return FALSE;
}
ClearProp( iProp );
ClearBit( & m_fPropIsVariantBits, iProp );
SetBit( & m_fPropInUseBits, iProp );
if( annoScope == ANNO_CONTAINER )
{
SetBit( & m_fContainerScopeBits, iProp );
}
else
{
ClearBit( & m_fContainerScopeBits, iProp );
}
m_Props[ iProp ].m_ServerInfo.m_dwMarshalDataLen = dwMarshalDataLen;
memcpy( pCopyData, pMarshalData, dwMarshalDataLen );
m_Props[ iProp ].m_ServerInfo.m_pMarshalData = pCopyData;
return TRUE;
}
void ClearProp( int i )
{
// Does this property need to be cleared?
if( IsBitSet( m_fPropInUseBits, i ) )
{
// Is it a simple variant, or a callback reference?
if( IsBitSet( m_fPropIsVariantBits, i ) )
{
// Simple variant...
VariantClear( & m_Props[ i ].m_var );
}
else
{
BYTE * pMarshalData = m_Props[ i ].m_ServerInfo.m_pMarshalData;
DWORD dwMarshalDataLen = m_Props[ i ].m_ServerInfo.m_dwMarshalDataLen;
// Callback reference...
Assert( dwMarshalDataLen );
if( dwMarshalDataLen && pMarshalData )
{
// This releases the object reference, byt we have to delete the buffer
// ourselves...
ReleaseMarshallData( pMarshalData, dwMarshalDataLen );
delete [ ] pMarshalData;
m_Props[ i ].m_ServerInfo.m_pMarshalData = NULL;
m_Props[ i ].m_ServerInfo.m_dwMarshalDataLen = 0;
}
}
ClearBit( & m_fPropInUseBits, i );
}
}
BOOL IsEmpty()
{
return m_fPropInUseBits == 0;
}
BOOL Alive()
{
return IsKeyAlive( m_pKeyData, m_dwKeyLen );
}
BOOL Sync()
{
return UpdateBlob();
}
private:
BYTE * AllocBlob( SIZE_T cbSize )
{
return (BYTE *) Alloc_32BitCompatible( cbSize );
}
void DeallocBlob( BYTE * pBlob )
{
Free_32BitCompatible( pBlob );
}
void ClearBlob()
{
if( m_pBlob )
{
RemoveProp( m_hwndProp, m_pKeyString );
DeallocBlob( m_pBlob );
m_pBlob = NULL;
}
}
BOOL UpdateBlob()
{
BYTE * pOldBlob = m_pBlob;
BYTE * pNewBlob = CalcBlob();
// We always update - even if pNewblob is NULL (ie. Calc failed)...
if( pNewBlob )
{
SetProp( m_hwndProp, m_pKeyString, pNewBlob );
}
else
{
RemoveProp( m_hwndProp, m_pKeyString );
}
if( pOldBlob )
{
DeallocBlob( pOldBlob );
}
m_pBlob = pNewBlob;
return TRUE;
}
BYTE * CalcBlob()
{
// If there are no properties being used, then we don't need anything at all.
if( ! m_fPropInUseBits )
{
return NULL;
}
// First, measure how much space we need...
// three constants...
SIZE_T dwSize = sizeof( DWORD ) * 4; // size header, m_fPropInUseBits, m_fPropIsVariantBits, m_fContainerScopeBits
// for each present property...
for( int i = 0 ; i < NUMPROPS ; i++ )
{
if( IsBitSet( m_fPropInUseBits, i ) )
{
if( IsBitSet( m_fPropIsVariantBits, i ) )
{
MemStreamMeasure_VARIANT( & dwSize, m_Props[ i ].m_var );
}
else
{
MemStreamMeasure_DWORD( & dwSize );
MemStreamMeasure_Binary( & dwSize, m_Props[ i ].m_ServerInfo.m_dwMarshalDataLen );
}
}
}
// Now allocate space...
BYTE * pBlob = AllocBlob( dwSize );
if( ! pBlob )
{
TraceError( TEXT("AccInfo::CalcBloc: AllocBlob returned NULL") );
return NULL;
}
// Finally write the data to the allocated space...
MemStream p( pBlob, dwSize );
MemStreamWrite_DWORD( p, (DWORD) dwSize );
MemStreamWrite_DWORD( p, m_fPropInUseBits );
MemStreamWrite_DWORD( p, m_fPropIsVariantBits );
MemStreamWrite_DWORD( p, m_fContainerScopeBits );
for( int j = 0 ; j < NUMPROPS ; j++ )
{
if( IsBitSet( m_fPropInUseBits, j ) )
{
if( IsBitSet( m_fPropIsVariantBits, j ) )
{
MemStreamWrite_VARIANT( p, m_Props[ j ].m_var );
}
else
{
MemStreamWrite_DWORD( p, m_Props[ j ].m_ServerInfo.m_dwMarshalDataLen );
MemStreamWrite_Binary( p, m_Props[ j ].m_ServerInfo.m_pMarshalData, m_Props[ j ].m_ServerInfo.m_dwMarshalDataLen );
}
}
}
// If we later decide to allow any GUIDs (other than the well-known ones which have indices) as props,
// we could add them here as GUID/VARIANT pairs.
return pBlob;
}
};
#define HWND_MESSAGE ((HWND)-3)
typedef std::map< AccObjKeyRef, AccInfo * > AccInfoMapType;
class CPropMgrImpl
{
AccInfoMapType m_Map;
BOOL m_fSelfLocked;
HWND m_hwnd;
int m_ref;
static
CPropMgrImpl * s_pThePropMgrImpl;
friend void PropMgrImpl_Uninit();
public:
CPropMgrImpl()
: m_fSelfLocked( FALSE ),
m_hwnd( NULL ),
m_ref( 1 )
{
_Module.Lock();
}
BOOL Init()
{
TCHAR szWindowName[ 32 ];
wsprintf( szWindowName, TEXT("MSAA_DA_%lx"), GetCurrentProcessId() );
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = StaticWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = _Module.GetModuleInstance();
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT("MSAA_DA_Class");
RegisterClass( & wc );
CreateWindow( TEXT("MSAA_DA_Class"),
szWindowName,
0,
0, 0, 128, 128,
NULL, NULL, _Module.GetModuleInstance(), this );
// Make this a message only window. We don't care if it fails, win9x case.
SetParent( m_hwnd, HWND_MESSAGE );
SetTimer( m_hwnd, 1, 5 * 1000, NULL );
return TRUE;
}
~CPropMgrImpl()
{
s_pThePropMgrImpl = NULL;
KillTimer( NULL, 1 );
if( m_hwnd )
{
SetWindowLongPtr( m_hwnd, GWLP_USERDATA, NULL );
DestroyWindow( m_hwnd );
}
_Module.Unlock();
}
void AddRef()
{
m_ref++;
}
void Release()
{
m_ref--;
if( m_ref == 0 )
{
delete this;
}
}
static
CPropMgrImpl * GetThePropMgrImpl()
{
if( ! s_pThePropMgrImpl )
{
s_pThePropMgrImpl = new CPropMgrImpl();
if( ! s_pThePropMgrImpl )
{
TraceError( TEXT("CPropMgrImpl::GetThePropMgrImpl: new returned NULL") );
return NULL;
}
if( ! s_pThePropMgrImpl->Init() )
{
delete s_pThePropMgrImpl;
s_pThePropMgrImpl = NULL;
TraceError( TEXT("CPropMgrImpl::GetThePropMgrImpl: s_pThePropMgrImpl->Init() returned FALSE") );
return NULL;
}
}
else
{
// We only addref the second and subsequent times that we
// hand out a pointer.
// The first time, we use the ref the the object had when it
// was created.
// (This static ptr s_pThePropMgrImpl is a weak reference.)
s_pThePropMgrImpl->AddRef();
}
return s_pThePropMgrImpl;
}
void Clean()
{
// Go through the elements in the map...
for( AccInfoMapType::iterator i = m_Map.begin() ; i != m_Map.end() ; )
{
// check if the key is still valid...
if( ! i->second->Alive() )
{
AccInfoMapType::iterator t = i;
i++;
AccInfo * pInfo = t->second;
m_Map.erase( t );
delete pInfo;
}
else
{
i++;
}
}
// Unload if necessary
CheckRef();
}
void ClearAll()
{
for( AccInfoMapType::iterator i = m_Map.begin() ; i != m_Map.end() ; )
{
AccInfoMapType::iterator t = i;
i++;
AccInfo * pInfo = t->second;
m_Map.erase( t );
delete pInfo;
}
// Unload if necessary
CheckRef();
}
void CheckRef()
{
if( m_Map.empty() )
{
if( m_fSelfLocked )
{
m_fSelfLocked = FALSE;
Release();
}
}
else
{
if( ! m_fSelfLocked )
{
m_fSelfLocked = TRUE;
AddRef();
}
}
}
AccInfo * LookupKey( const BYTE * pKeyData, DWORD dwKeyLen, BOOL fCreate )
{
AccInfoMapType::iterator i;
AccObjKeyRef keyref( pKeyData, dwKeyLen );
i = m_Map.find( keyref );
if( i == m_Map.end() || i->first != keyref )
{
// insert...
if( fCreate )
{
AccInfo * pInfo = new AccInfo;
if( ! pInfo )
{
TraceError( TEXT("CPropMgrImpl::LookupKey: new returned NULL") );
return NULL;
}
// If the key is associated with a HWND, use that; otherwise attach the key to our own window.
HWND hwndProp;
if( ! DecodeHwndKey( pKeyData, dwKeyLen, & hwndProp, NULL, NULL ) )
{
hwndProp = m_hwnd;
}
pInfo->Init( pKeyData, dwKeyLen, hwndProp );
m_Map.insert( std::make_pair( pInfo->GetKeyRef(), pInfo ) );
// make sure we're locked...
CheckRef();
return pInfo;
}
else
{
return NULL;
}
}
else
{
return i->second;
}
}
void RemoveEntry( AccInfo * pInfo )
{
m_Map.erase( pInfo->GetKeyRef() );
// if we're empty, we can unlock the module...
CheckRef();
}
HRESULT ValidateArray( const void * pvStart, int cLen, int elsize, LPCTSTR pMethodName, LPCTSTR pPtrName, LPCTSTR pLenName )
{
// Parameter checking...
if( ! pvStart )
{
TraceParam( TEXT("%s: %s is NULL"), pMethodName, pPtrName );
return E_POINTER;
}
if( cLen <= 0 )
{
TraceParam( TEXT("%s: %s is <= 0"), pMethodName, pLenName );
return E_INVALIDARG;
}
if( IsBadReadPtr( pvStart, cLen * elsize ) )
{
TraceParam( TEXT("%s: %s/%s points to non-readable memory"), pMethodName, pPtrName, pLenName );
return E_POINTER;
}
return S_OK;
}
HRESULT SetPropValue( const BYTE * pKeyData,
DWORD dwKeyLen,
MSAAPROPID idProp,
VARIANT * pvarValue )
{
// Parameter checking...
HRESULT hr = ValidateArray( pKeyData, dwKeyLen, sizeof(BYTE), TEXT("SetPropValue"), TEXT("pKeyData"), TEXT("dwKeyLen") );
if( hr != S_OK )
return hr;
if( pvarValue == NULL )
{
TraceParam( TEXT("CPropMgrImpl::SetPropValue: pvarValue is NULL") );
return E_POINTER;
}
AccInfo * pInfo = LookupKey( pKeyData, dwKeyLen, TRUE );
Assert( pInfo );
if( ! pInfo )
{
TraceParam( TEXT("CPropMgrImpl::SetPropValue: key not found") );
return E_INVALIDARG;
}
int idxProp = IndexFromProp( idProp );
if( idxProp == -1 )
{
TraceParam( TEXT("CPropMgrImpl::SetPropValue: unknown prop") );
return E_INVALIDARG;
}
// check type...
if( pvarValue->vt != g_PropInfo[ idxProp ].m_Type )
{
TraceParam( TEXT("CPropMgrImpl::SetPropValue: incorrect type for property") );
return E_INVALIDARG;
}
// Do we support setting this property directly?
// (Some can be returned via callbacks only, not set directly)
if( ! g_PropInfo[ idxProp ].m_fSupportSetValue )
{
TraceParam( TEXT("CPropMgrImpl::SetPropValue: prop does not support direct set") );
return E_INVALIDARG;
}
if( ! pInfo->SetPropValue( idxProp, pvarValue ) )
{
return E_FAIL;
}
pInfo->Sync();
return S_OK;
}
HRESULT ClearProps( const BYTE * pKeyData,
DWORD dwKeyLen,
const MSAAPROPID * paProps,
int cProps )
{
// Parameter checking...
HRESULT hr = ValidateArray( pKeyData, dwKeyLen, sizeof(BYTE), TEXT("ClearProps"), TEXT("pKeyData"), TEXT("dwKeyLen") );
if( hr != S_OK )
return hr;
hr = ValidateArray( paProps, cProps, sizeof(MSAAPROPID), TEXT("ClearProps"), TEXT("paProps"), TEXT("cProps") );
if( hr != S_OK )
return hr;
AccInfo * pInfo = LookupKey( pKeyData, dwKeyLen, FALSE );
Assert( pInfo );
if( ! pInfo )
{
TraceParam( TEXT("CPropMgrImpl::SetPropValue: key not found") );
return E_INVALIDARG;
}
BOOL fUnknownProp = FALSE;
for( int i = 0 ; i < cProps ; i++ )
{
int idxProp = IndexFromProp( paProps[ i ] );
if( idxProp == -1 )
{
TraceParam( TEXT("CPropMgrImpl::ClearProps: unknown prop") );
fUnknownProp = TRUE;
// Continue and clear the other props that we do recognize...
}
else
{
pInfo->ClearProp( idxProp );
}
}
pInfo->Sync();
if( pInfo->IsEmpty() )
{
RemoveEntry( pInfo );
}
return fUnknownProp ? E_INVALIDARG : S_OK;
}
HRESULT SetPropServer( const BYTE * pKeyData,
DWORD dwKeyLen,
const MSAAPROPID * paProps,
int cProps,
const BYTE * pMarshalData,
int dwMarshalDataLen,
AnnoScope annoScope )
{
// Parameter checking...
HRESULT hr = ValidateArray( pKeyData, dwKeyLen, sizeof(BYTE), TEXT("SetPropServer"), TEXT("pKeyData"), TEXT("dwKeyLen") );
if( hr != S_OK )
return hr;
hr = ValidateArray( paProps, cProps, sizeof(MSAAPROPID), TEXT("SetPropServer"), TEXT("paProps"), TEXT("cProps") );
if( hr != S_OK )
return hr;
AccInfo * pInfo = LookupKey( pKeyData, dwKeyLen, TRUE );
Assert( pInfo );
if( ! pInfo )
{
TraceParam( TEXT("CPropMgrImpl::SetPropValue: key not found") );
return E_INVALIDARG;
}
// TODO - make this two-pass - validate props first,
// add them later - to make this atomic.
// (either all or none of the props should be registered)
for( int i = 0 ; i < cProps ; i++ )
{
int idxProp = IndexFromProp( paProps[ i ] );
if( idxProp == -1 )
{
TraceParam( TEXT("CPropMgrImpl::SetPropServer: unknown prop") );
return E_INVALIDARG;
}
if( ! pInfo->SetPropServer( idxProp, pMarshalData, dwMarshalDataLen, annoScope ) )
{
return E_FAIL;
}
}
pInfo->Sync();
return S_OK;
}
LRESULT WndProc( HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam )
{
if( uMsg == WM_TIMER )
{
Clean();
}
return DefWindowProc( hwnd, uMsg, wParam, lParam );
}
static
LRESULT CALLBACK StaticWndProc( HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam )
{
CPropMgrImpl * pThis = (CPropMgrImpl *) GetWindowLongPtr( hwnd, GWLP_USERDATA );
if( pThis )
{
return pThis->WndProc( hwnd, uMsg, wParam, lParam );
}
else if( uMsg == WM_NCCREATE )
{
LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam;
pThis = (CPropMgrImpl *)lpcs->lpCreateParams;
SetWindowLongPtr( hwnd, GWLP_USERDATA, (DWORD_PTR) pThis );
pThis->m_hwnd = hwnd;
return pThis->WndProc( hwnd, uMsg, wParam, lParam );
}
return DefWindowProc( hwnd, uMsg, wParam, lParam );
}
};
CPropMgrImpl * CPropMgrImpl::s_pThePropMgrImpl = NULL;
// If all annotated windows disappear before the app shuts down, or if all
// annotations are cleared, then everything gets cleaned up nicely.
//
// However, if CoUninitialize is called while controls are still annotated,
// we will need to explicitly clean up before COM unloads our dll.
//
// (If we don't, then (a) we leak memory, and (b) the DA window will
// still receive WM_TIMER messages to a wndproc that has been unloaded
// causin ga fault.)
//
// This is called from DLLMain's PROCESS_DETACH.
void PropMgrImpl_Uninit()
{
// Check if there is a Mgr in the first place...
CPropMgrImpl * pTheMgr = CPropMgrImpl::s_pThePropMgrImpl;
// No mgr - nothing to clean up.
if( ! pTheMgr )
return;
// AddRef it, to keep it alive while we're using it.
pTheMgr->AddRef();
// Clear all properties
pTheMgr->ClearAll();
// This release will cause the mgr to delete itself, since it is now empty.
pTheMgr->Release();
}
CPropMgr::CPropMgr()
{
IMETHOD( TEXT("CPropMgr::CPropMgr") );
m_pMgrImpl = CPropMgrImpl::GetThePropMgrImpl();
if( ! m_pMgrImpl )
{
TraceError( TEXT("CPropMgr::CPropMgr: CPropMgrImpl::GetThePropMgrImpl returned NULL") );
}
}
CPropMgr::~CPropMgr()
{
IMETHOD( TEXT("CPropMgr::~CPropMgr") );
if( m_pMgrImpl )
{
m_pMgrImpl->Release();
}
}
HRESULT STDMETHODCALLTYPE
CPropMgr::SetPropValue (
const BYTE * pIDString,
DWORD dwIDStringLen,
MSAAPROPID idProp,
VARIANT var
)
{
IMETHOD( TEXT("CPropMgr::SetPropValue") );
if( ! m_pMgrImpl )
return E_FAIL;
return m_pMgrImpl->SetPropValue( pIDString, dwIDStringLen, idProp, & var );
}
HRESULT STDMETHODCALLTYPE
CPropMgr::SetPropServer (
const BYTE * pIDString,
DWORD dwIDStringLen,
const MSAAPROPID * paProps,
int cProps,
IAccPropServer * pServer,
AnnoScope annoScope
)
{
IMETHOD( TEXT("CPropMgr::SetPropServer"), TEXT("cProps=%d"), cProps );
if( ! m_pMgrImpl )
return E_FAIL;
const BYTE * pData;
DWORD dwDataLen;
MarshalState mstate;
// We use strong table marshalling to keep the object alive until we free it.
// (Ownership is actually transferred to the property manager, which will release it when
// either the property is cleared explicity, or after the HWND dies and it gets swept away.)
HRESULT hr = MarshalInterface( IID_IAccPropServer, pServer, MSHCTX_LOCAL, MSHLFLAGS_TABLESTRONG,
& pData, & dwDataLen, & mstate );
if( FAILED( hr ) )
{
TraceErrorHR( hr, TEXT("CPropMgr::SetPropServer: MarshalInterface failed") );
return hr;
}
hr = m_pMgrImpl->SetPropServer( pIDString, dwIDStringLen, paProps, cProps, pData, dwDataLen, annoScope );
MarshalInterfaceDone( & mstate );
return hr;
}
HRESULT STDMETHODCALLTYPE
CPropMgr::ClearProps (
const BYTE * pIDString,
DWORD dwIDStringLen,
const MSAAPROPID * paProps,
int cProps
)
{
IMETHOD( TEXT("CPropMgr::ClearProps"), TEXT("cProps=%d"), cProps );
if( ! m_pMgrImpl )
return E_FAIL;
return m_pMgrImpl->ClearProps( pIDString, dwIDStringLen, paProps, cProps );
}
// Quick OLEACC/HWND-based functionality
HRESULT STDMETHODCALLTYPE
CPropMgr::SetHwndProp (
HWND hwnd,
DWORD idObject,
DWORD idChild,
MSAAPROPID idProp,
VARIANT var
)
{
IMETHOD( TEXT("CPropMgr::SetHwndProp") );
if( ! m_pMgrImpl )
return E_FAIL;
BYTE HwndKey [ HWNDKEYSIZE ];
MakeHwndKey( HwndKey, hwnd, idObject, idChild );
return m_pMgrImpl->SetPropValue( HwndKey, HWNDKEYSIZE, idProp, & var );
}
HRESULT STDMETHODCALLTYPE
CPropMgr::SetHwndPropStr (
HWND hwnd,
DWORD idObject,
DWORD idChild,
MSAAPROPID idProp,
LPCWSTR str
)
{
IMETHOD( TEXT("CPropMgr::SetHwndPropStr") );
if( ! m_pMgrImpl )
return E_FAIL;
// Need to convert the LPCWSTR to a BSTR before we can put it into a variant...
VARIANT var;
var.vt = VT_BSTR;
var.bstrVal = SysAllocString( str );
if( ! var.bstrVal )
{
TraceError( TEXT("CPropMgr::SetHwndPropStr: SysAllocString failed") );
return E_OUTOFMEMORY;
}
BYTE HwndKey [ HWNDKEYSIZE ];
MakeHwndKey( HwndKey, hwnd, idObject, idChild );
HRESULT hr = m_pMgrImpl->SetPropValue( HwndKey, HWNDKEYSIZE, idProp, & var );
SysFreeString( var.bstrVal );
return hr;
}
HRESULT STDMETHODCALLTYPE
CPropMgr::SetHwndPropServer (
HWND hwnd,
DWORD idObject,
DWORD idChild,
const MSAAPROPID * paProps,
int cProps,
IAccPropServer * pServer,
AnnoScope annoScope
)
{
IMETHOD( TEXT("CPropMgr::SetHwndPropServer") );
if( ! m_pMgrImpl )
return E_FAIL;
BYTE HwndKey [ HWNDKEYSIZE ];
MakeHwndKey( HwndKey, hwnd, idObject, idChild );
return SetPropServer( HwndKey, HWNDKEYSIZE, paProps, cProps, pServer, annoScope );
}
HRESULT STDMETHODCALLTYPE
CPropMgr::ClearHwndProps (
HWND hwnd,
DWORD idObject,
DWORD idChild,
const MSAAPROPID * paProps,
int cProps
)
{
IMETHOD( TEXT("CPropMgr::ClearHwndProps") );
if( ! m_pMgrImpl )
return E_FAIL;
BYTE HwndKey [ HWNDKEYSIZE ];
MakeHwndKey( HwndKey, hwnd, idObject, idChild );
return ClearProps( HwndKey, HWNDKEYSIZE, paProps, cProps );
}
// Methods for composing/decomposing a HWND-based key...
HRESULT STDMETHODCALLTYPE
CPropMgr::ComposeHwndIdentityString (
HWND hwnd,
DWORD idObject,
DWORD idChild,
BYTE ** ppIDString,
DWORD * pdwIDStringLen
)
{
IMETHOD( TEXT("CPropMgr::ComposeHwndIdentityString") );
*ppIDString = NULL;
*pdwIDStringLen = 0;
BYTE * pKeyData = (BYTE *)CoTaskMemAlloc( HWNDKEYSIZE );
if( ! pKeyData )
{
TraceError( TEXT("CPropMgr::ComposeHwndIdentityString: CoTaskMemAlloc failed") );
return E_OUTOFMEMORY;
}
MakeHwndKey( pKeyData, hwnd, idObject, idChild );
*ppIDString = pKeyData;
*pdwIDStringLen = HWNDKEYSIZE;
return S_OK;
}
HRESULT STDMETHODCALLTYPE
CPropMgr::DecomposeHwndIdentityString (
const BYTE * pIDString,
DWORD dwIDStringLen,
HWND * phwnd,
DWORD * pidObject,
DWORD * pidChild
)
{
IMETHOD( TEXT("CPropMgr::DecomposeHwndIdentityString") );
if( ! DecodeHwndKey( pIDString, dwIDStringLen, phwnd, pidObject, pidChild ) )
{
TraceParam( TEXT("CPropMgr::DecomposeHwndIdentityString: not a valid HWND id string") );
return E_INVALIDARG;
}
return S_OK;
}
// Quick OLEACC/HMENU-based functionality
HRESULT STDMETHODCALLTYPE
CPropMgr::SetHmenuProp (
HMENU hmenu,
DWORD idChild,
MSAAPROPID idProp,
VARIANT var
)
{
IMETHOD( TEXT("CPropMgr::SetHmenuProp") );
if( ! m_pMgrImpl )
return E_FAIL;
BYTE HmenuKey [ HMENUKEYSIZE ];
MakeHmenuKey( HmenuKey, GetCurrentProcessId(), hmenu, idChild );
return m_pMgrImpl->SetPropValue( HmenuKey, HMENUKEYSIZE, idProp, & var );
}
HRESULT STDMETHODCALLTYPE
CPropMgr::SetHmenuPropStr (
HMENU hmenu,
DWORD idChild,
MSAAPROPID idProp,
LPCWSTR str
)
{
IMETHOD( TEXT("CPropMgr::SetHmenuPropStr") );
if( ! m_pMgrImpl )
return E_FAIL;
// Need to convert the LPCWSTR to a BSTR before we can put it into a variant...
VARIANT var;
var.vt = VT_BSTR;
var.bstrVal = SysAllocString( str );
if( ! var.bstrVal )
{
TraceError( TEXT("CPropMgr::SetHmenuPropStr: SysAllocString failed") );
return E_OUTOFMEMORY;
}
BYTE HmenuKey [ HMENUKEYSIZE ];
MakeHmenuKey( HmenuKey, GetCurrentProcessId(), hmenu, idChild );
HRESULT hr = m_pMgrImpl->SetPropValue( HmenuKey, HMENUKEYSIZE, idProp, & var );
SysFreeString( var.bstrVal );
return hr;
}
HRESULT STDMETHODCALLTYPE
CPropMgr::SetHmenuPropServer (
HMENU hmenu,
DWORD idChild,
const MSAAPROPID * paProps,
int cProps,
IAccPropServer * pServer,
AnnoScope annoScope
)
{
IMETHOD( TEXT("CPropMgr::SetHmenuPropServer") );
if( ! m_pMgrImpl )
return E_FAIL;
BYTE HmenuKey [ HMENUKEYSIZE ];
MakeHmenuKey( HmenuKey, GetCurrentProcessId(), hmenu, idChild );
return SetPropServer( HmenuKey, HMENUKEYSIZE, paProps, cProps, pServer, annoScope );
}
HRESULT STDMETHODCALLTYPE
CPropMgr::ClearHmenuProps (
HMENU hmenu,
DWORD idChild,
const MSAAPROPID * paProps,
int cProps
)
{
IMETHOD( TEXT("CPropMgr::ClearHmenuProps") );
if( ! m_pMgrImpl )
return E_FAIL;
BYTE HmenuKey [ HMENUKEYSIZE ];
MakeHmenuKey( HmenuKey, GetCurrentProcessId(), hmenu, idChild );
return ClearProps( HmenuKey, HMENUKEYSIZE, paProps, cProps );
}
// Methods for composing/decomposing a HMENU-based key...
HRESULT STDMETHODCALLTYPE
CPropMgr::ComposeHmenuIdentityString (
HMENU hmenu,
DWORD idChild,
BYTE ** ppIDString,
DWORD * pdwIDStringLen
)
{
IMETHOD( TEXT("CPropMgr::ComposeHmenuIdentityString") );
*ppIDString = NULL;
*pdwIDStringLen = 0;
BYTE * pKeyData = (BYTE *)CoTaskMemAlloc( HMENUKEYSIZE );
if( ! pKeyData )
{
TraceError( TEXT("CPropMgr::ComposeHmenuIdentityString: CoTaskMemAlloc failed") );
return E_OUTOFMEMORY;
}
MakeHmenuKey( pKeyData, GetCurrentProcessId(), hmenu, idChild );
*ppIDString = pKeyData;
*pdwIDStringLen = HMENUKEYSIZE;
return S_OK;
}
HRESULT STDMETHODCALLTYPE
CPropMgr::DecomposeHmenuIdentityString (
const BYTE * pIDString,
DWORD dwIDStringLen,
HMENU * phmenu,
DWORD * pidChild
)
{
IMETHOD( TEXT("CPropMgr::DecomposeHmenuIdentityString") );
if( ! DecodeHmenuKey( pIDString, dwIDStringLen, NULL, phmenu, pidChild ) )
{
TraceParam( TEXT("CPropMgr::DecomposeHmenuIdentityString: not a valid HMENU id string") );
return E_INVALIDARG;
}
return S_OK;
}