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.
587 lines
14 KiB
587 lines
14 KiB
/************************************************************************
|
|
|
|
Copyright (c) 2002 Microsoft Corporation
|
|
|
|
Module Name :
|
|
|
|
smartptr.h
|
|
|
|
Abstract :
|
|
|
|
This file contains a class for implementing smart ref counted pointers.
|
|
|
|
Author :
|
|
|
|
Mike Zoran mzoran Feb 2002.
|
|
|
|
Revision History :
|
|
|
|
***********************************************************************/
|
|
|
|
#if !defined( _BITS_SMARTPTR_H )
|
|
|
|
#include <strsafe.h>
|
|
|
|
#define ARRAY_ELEMENTS( array ) ( sizeof( array ) / sizeof( *(array) ) )
|
|
|
|
class ComError
|
|
{
|
|
|
|
public:
|
|
HRESULT m_Hr;
|
|
|
|
ComError( const ComError & Other ) :
|
|
m_Hr( Other.m_Hr )
|
|
{
|
|
}
|
|
|
|
ComError( HRESULT Hr ) :
|
|
m_Hr( Hr )
|
|
{
|
|
}
|
|
};
|
|
|
|
inline void THROW_COMERROR( HRESULT Hr )
|
|
{
|
|
if ( FAILED( Hr ) )
|
|
throw ComError( Hr );
|
|
}
|
|
|
|
inline void THROW_OUTOFMEMORY_IFNULL( void *p )
|
|
{
|
|
if (p == NULL)
|
|
throw ComError( E_OUTOFMEMORY );
|
|
}
|
|
|
|
template<class T> class SmartRefPointer
|
|
{
|
|
private:
|
|
T * m_Interface;
|
|
|
|
void ReleaseIt()
|
|
{
|
|
if ( m_Interface )
|
|
m_Interface->Release();
|
|
m_Interface = NULL;
|
|
}
|
|
|
|
void RefIt()
|
|
{
|
|
if ( m_Interface )
|
|
m_Interface->AddRef();
|
|
}
|
|
|
|
public:
|
|
|
|
SmartRefPointer()
|
|
{
|
|
m_Interface = NULL;
|
|
}
|
|
|
|
SmartRefPointer( T * RawInterface )
|
|
{
|
|
m_Interface = RawInterface;
|
|
RefIt();
|
|
}
|
|
|
|
SmartRefPointer( SmartRefPointer & Other )
|
|
{
|
|
m_Interface = Other.m_Interface;
|
|
RefIt();
|
|
}
|
|
|
|
~SmartRefPointer()
|
|
{
|
|
ReleaseIt();
|
|
}
|
|
|
|
T * Get() const
|
|
{
|
|
return m_Interface;
|
|
}
|
|
|
|
T * Release()
|
|
{
|
|
T * temp = m_Interface;
|
|
m_Interface = NULL;
|
|
return temp;
|
|
}
|
|
|
|
void Clear()
|
|
{
|
|
ReleaseIt();
|
|
}
|
|
|
|
T** GetRecvPointer()
|
|
{
|
|
ReleaseIt();
|
|
return &m_Interface;
|
|
}
|
|
|
|
SmartRefPointer & operator=( SmartRefPointer & Other )
|
|
{
|
|
ReleaseIt();
|
|
m_Interface = Other.m_Interface;
|
|
RefIt();
|
|
return *this;
|
|
}
|
|
|
|
T* operator->() const
|
|
{
|
|
return m_Interface;
|
|
}
|
|
|
|
operator const T*() const
|
|
{
|
|
return m_Interface;
|
|
}
|
|
|
|
const GUID & GetUUID() const
|
|
{
|
|
return __uuidof( T );
|
|
}
|
|
};
|
|
|
|
typedef SmartRefPointer<IUnknown> SmartIUnknownPointer;
|
|
typedef SmartRefPointer<IDispatch> SmartIDispatchPointer;
|
|
|
|
class SmartVariant : public VARIANT
|
|
{
|
|
public:
|
|
SmartVariant()
|
|
{
|
|
VariantInit( this );
|
|
}
|
|
~SmartVariant()
|
|
{
|
|
VariantClear( this );
|
|
}
|
|
};
|
|
|
|
class SafeArrayLocker
|
|
{
|
|
SAFEARRAY* m_Array;
|
|
bool m_Locked;
|
|
|
|
public:
|
|
SafeArrayLocker(
|
|
SAFEARRAY* Array,
|
|
bool Locked = false ) :
|
|
m_Array( Array ),
|
|
m_Locked( Locked )
|
|
{
|
|
}
|
|
~SafeArrayLocker()
|
|
{
|
|
Unlock();
|
|
}
|
|
void Lock()
|
|
{
|
|
if ( m_Array && !m_Locked )
|
|
{
|
|
THROW_COMERROR( SafeArrayLock( m_Array ) );
|
|
m_Locked = true;
|
|
}
|
|
}
|
|
void Unlock()
|
|
{
|
|
if ( m_Array && m_Locked )
|
|
{
|
|
THROW_COMERROR( SafeArrayUnlock( m_Array ) );
|
|
m_Locked = false;
|
|
}
|
|
}
|
|
};
|
|
|
|
template<class T>
|
|
class MemoryArrayCleaner
|
|
{
|
|
T *& m_Pointer;
|
|
public:
|
|
MemoryArrayCleaner( T *& Pointer ) :
|
|
m_Pointer( Pointer )
|
|
{
|
|
}
|
|
~MemoryArrayCleaner()
|
|
{
|
|
delete[] m_Pointer;
|
|
m_Pointer = NULL;
|
|
}
|
|
};
|
|
|
|
class CharStringRoutines
|
|
{
|
|
|
|
public:
|
|
static int strcmp( const char *str1, const char *str2 )
|
|
{
|
|
return ::strcmp( str1, str2 );
|
|
}
|
|
|
|
static HRESULT StringCchCopy( char *str1, size_t cchDest, const char *str2 )
|
|
{
|
|
return ::StringCchCopyA( str1, cchDest, str2 );
|
|
}
|
|
|
|
static size_t strlen( const char *str )
|
|
{
|
|
return ::strlen( str );
|
|
}
|
|
|
|
static void* ConvertToInternal( SIZE_T Pad, const char *String, SIZE_T & Size )
|
|
{
|
|
Size = ::strlen( String );
|
|
char *Ret = new char[ Pad + Size + 1 ];
|
|
::StringCchCopyA( Ret + Pad, Size + 1, String );
|
|
return (void*)Ret;
|
|
}
|
|
|
|
static void* ConvertToInternal( SIZE_T Pad, const WCHAR *String, SIZE_T & Size )
|
|
{
|
|
|
|
int Alloc =
|
|
WideCharToMultiByte(
|
|
CP_THREAD_ACP, // code page
|
|
0, // performance and mapping flags
|
|
String, // wide-character string
|
|
-1, // number of chars in string
|
|
NULL, // buffer for new string
|
|
0, // size of buffer
|
|
NULL, // default for unmappable chars
|
|
NULL // set when default char used
|
|
);
|
|
|
|
if ( !Alloc )
|
|
throw ComError( HRESULT_FROM_WIN32( GetLastError() ) );
|
|
|
|
char *Ret = new char[ Pad + Alloc ];
|
|
|
|
int Actual =
|
|
WideCharToMultiByte(
|
|
CP_THREAD_ACP, // code page
|
|
0, // performance and mapping flags
|
|
String, // wide-character string
|
|
-1, // number of chars in string
|
|
Ret + Pad, // buffer for new string
|
|
Alloc, // size of buffer
|
|
NULL, // default for unmappable chars
|
|
NULL // set when default char used
|
|
);
|
|
|
|
if ( !Actual )
|
|
{
|
|
HRESULT Hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
delete[] Ret;
|
|
throw ComError( Hr );
|
|
}
|
|
|
|
Size = Actual - 1;
|
|
return Ret;
|
|
|
|
}
|
|
};
|
|
|
|
class WCHARStringRoutines
|
|
{
|
|
|
|
public:
|
|
static int strcmp( const WCHAR *str1, const WCHAR *str2 )
|
|
{
|
|
return ::wcscmp( str1, str2 );
|
|
}
|
|
|
|
static HRESULT StringCchCopy( WCHAR *str1, size_t cchDest, const WCHAR *str2 )
|
|
{
|
|
return ::StringCchCopyW( str1, cchDest, str2 );
|
|
}
|
|
|
|
static size_t strlen( const wchar_t *str )
|
|
{
|
|
return ::wcslen( str );
|
|
}
|
|
|
|
static void* ConvertToInternal( SIZE_T Pad, const WCHAR *String, SIZE_T & Size )
|
|
{
|
|
Size = ::wcslen( String );
|
|
char *Ret = new char[ Pad + ( ( Size + 1 ) * sizeof(WCHAR) ) ];
|
|
::StringCchCopyW( (WCHAR*)(Ret + Pad), Size + 1, String );
|
|
return (void*)Ret;
|
|
}
|
|
|
|
static void* ConvertToInternal( SIZE_T Pad, const char *String, SIZE_T & Size )
|
|
{
|
|
|
|
int Alloc =
|
|
MultiByteToWideChar(
|
|
CP_THREAD_ACP, // code page
|
|
0, // character-type options
|
|
String, // string to map
|
|
-1, // number of bytes in string
|
|
NULL, // wide-character buffer
|
|
0 // size of buffer
|
|
);
|
|
|
|
if ( !Alloc )
|
|
throw ComError( HRESULT_FROM_WIN32( GetLastError() ) );
|
|
|
|
char *Ret = new char[ Pad + ( Alloc * sizeof(WCHAR) ) ];
|
|
|
|
int Actual =
|
|
MultiByteToWideChar(
|
|
CP_THREAD_ACP, // code page
|
|
0, // character-type options
|
|
String, // string to map
|
|
-1, // number of bytes in string
|
|
(WCHAR*)( Ret + Pad ), // wide-character buffer
|
|
Alloc // size of buffer
|
|
);
|
|
|
|
if ( !Actual )
|
|
{
|
|
HRESULT Hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
delete[] Ret;
|
|
throw ComError( Hr );
|
|
}
|
|
|
|
Size = Actual - 1;
|
|
return Ret;
|
|
|
|
}
|
|
};
|
|
|
|
template<class T, class CONV>
|
|
class StringHandleTemplate : private CONV
|
|
{
|
|
|
|
struct StringData
|
|
{
|
|
SIZE_T m_Count;
|
|
long m_Refs;
|
|
};
|
|
|
|
struct EmptyStringData
|
|
{
|
|
StringData m_StringData;
|
|
T m_Data;
|
|
};
|
|
|
|
static EmptyStringData s_EmptyString;
|
|
|
|
StringData *m_Value;
|
|
|
|
void NewString( const char *String, bool ReplaceExisting = false );
|
|
void NewString( const WCHAR *String, bool ReplaceExisting = false );
|
|
|
|
StringData * RefIt() const
|
|
{
|
|
InterlockedIncrement( &m_Value->m_Refs );
|
|
return m_Value;
|
|
}
|
|
|
|
void FreeIt()
|
|
{
|
|
if ( m_Value->m_Refs && InterlockedDecrement( &m_Value->m_Refs ) == 0 )
|
|
{
|
|
delete [] m_Value;
|
|
m_Value = NULL;
|
|
}
|
|
}
|
|
|
|
// Create String by concating 2 strings
|
|
StringHandleTemplate( const StringData *LeftValue, const T *RightValue, SIZE_T RightSize );
|
|
|
|
|
|
public:
|
|
|
|
StringHandleTemplate()
|
|
{
|
|
NewString( (T*)NULL );
|
|
}
|
|
|
|
StringHandleTemplate( const char *String )
|
|
{
|
|
NewString( String );
|
|
}
|
|
|
|
StringHandleTemplate( const WCHAR *String )
|
|
{
|
|
NewString( String );
|
|
}
|
|
|
|
|
|
StringHandleTemplate( const StringHandleTemplate & Other ) :
|
|
m_Value( Other.RefIt() )
|
|
{
|
|
}
|
|
|
|
~StringHandleTemplate()
|
|
{
|
|
FreeIt();
|
|
}
|
|
|
|
void SetStringSize()
|
|
{
|
|
m_Value->m_Count = strlen( (T*)(m_Value + 1) );
|
|
}
|
|
|
|
T *AllocBuffer( SIZE_T Size );
|
|
|
|
StringHandleTemplate & operator=( const StringHandleTemplate & r )
|
|
{
|
|
FreeIt();
|
|
m_Value = r.RefIt();
|
|
return *this;
|
|
}
|
|
|
|
StringHandleTemplate & operator=( const T * r )
|
|
{
|
|
NewString( r, true );
|
|
return *this;
|
|
}
|
|
|
|
SIZE_T Size() const
|
|
{
|
|
return m_Value->m_Count;
|
|
}
|
|
|
|
operator const T*() const
|
|
{
|
|
return (const T*)(m_Value + 1);
|
|
}
|
|
|
|
bool operator <( const StringHandleTemplate & r ) const
|
|
{
|
|
if ( m_Value == r.m_Value)
|
|
return false;
|
|
return (strcmp( (const T*)*this, (const T*)r ) < 0);
|
|
}
|
|
|
|
StringHandleTemplate operator+( const StringHandleTemplate & r ) const
|
|
{
|
|
return StringHandleTemplate( m_Value, (T*)(r.m_Value+1), r.m_Value->m_Count );
|
|
}
|
|
|
|
StringHandleTemplate operator+( const T * p ) const
|
|
{
|
|
static const T EmptyChar = '\0';
|
|
|
|
if ( !p )
|
|
return StringHandleTemplate( m_Value, &EmptyChar, 0 );
|
|
|
|
return StringHandleTemplate( m_Value, p, strlen(p) );
|
|
}
|
|
StringHandleTemplate & operator+=( const StringHandleTemplate & r )
|
|
{
|
|
return (*this = (*this + r ) );
|
|
}
|
|
StringHandleTemplate & operator+=( const T * p )
|
|
{
|
|
return (*this = (*this + p ) );
|
|
}
|
|
};
|
|
|
|
template<class T,class CONV>
|
|
void
|
|
StringHandleTemplate<T,CONV>::NewString( const char *String, bool ReplaceExisting )
|
|
{
|
|
if ( !String )
|
|
{
|
|
|
|
InterlockedIncrement( &s_EmptyString.m_StringData.m_Refs );
|
|
StringData* Value = (StringData*)&s_EmptyString;
|
|
|
|
if ( ReplaceExisting )
|
|
FreeIt();
|
|
|
|
m_Value = Value;
|
|
return;
|
|
|
|
}
|
|
|
|
SIZE_T Size;
|
|
StringData* Value = (StringData*)ConvertToInternal( sizeof(StringData), String, Size );
|
|
Value->m_Count = Size;
|
|
Value->m_Refs = 1;
|
|
|
|
if ( ReplaceExisting )
|
|
FreeIt();
|
|
|
|
m_Value = Value;
|
|
|
|
}
|
|
|
|
template<class T,class CONV>
|
|
void
|
|
StringHandleTemplate<T,CONV>::NewString( const WCHAR *String, bool ReplaceExisting )
|
|
{
|
|
|
|
if ( !String )
|
|
{
|
|
InterlockedIncrement( &s_EmptyString.m_StringData.m_Refs );
|
|
StringData* Value = (StringData*)&s_EmptyString;
|
|
|
|
if ( ReplaceExisting )
|
|
FreeIt();
|
|
|
|
m_Value = Value;
|
|
return;
|
|
}
|
|
|
|
SIZE_T Size;
|
|
StringData* Value = (StringData*)ConvertToInternal( sizeof(StringData), String, Size );
|
|
Value->m_Count = Size;
|
|
Value->m_Refs = 1;
|
|
|
|
if ( ReplaceExisting )
|
|
FreeIt();
|
|
|
|
m_Value = Value;
|
|
|
|
}
|
|
|
|
|
|
// Create String by concating 2 strings
|
|
template<class T,class CONV>
|
|
StringHandleTemplate<T,CONV>::StringHandleTemplate( const StringData *LeftValue, const T *RightValue, SIZE_T RightSize )
|
|
{
|
|
SIZE_T Size = LeftValue->m_Count + RightSize;
|
|
m_Value = (StringData*)new char[ sizeof(StringData) + (Size*sizeof(T)) + sizeof(T) ];
|
|
m_Value->m_Count = Size;
|
|
m_Value->m_Refs = 1;
|
|
|
|
T *DestData = (T*)( m_Value + 1 );
|
|
memcpy( DestData, (T*)(LeftValue + 1), sizeof(T) * LeftValue->m_Count );
|
|
memcpy( DestData + LeftValue->m_Count, RightValue, sizeof( T ) * RightSize );
|
|
DestData[ Size ] = 0;
|
|
}
|
|
|
|
|
|
template<class T,class CONV>
|
|
T *
|
|
StringHandleTemplate<T,CONV>::AllocBuffer( SIZE_T Size )
|
|
{
|
|
StringData *Data = (StringData*)new T[sizeof(StringData)+(Size*sizeof(T))+sizeof(T)];
|
|
Data->m_Count = 0;
|
|
Data->m_Refs = 1;
|
|
T *String = (T*)(Data + 1);
|
|
String[0] = '\0';
|
|
|
|
FreeIt(); // Free old string
|
|
m_Value = Data;
|
|
|
|
// Whoever fills in the string needs to call SetStringSize
|
|
return String;
|
|
|
|
}
|
|
|
|
template<class T,class CONV>
|
|
typename StringHandleTemplate<T,CONV>::EmptyStringData StringHandleTemplate<T,CONV>::s_EmptyString =
|
|
{
|
|
0, 1, L'\0' // Initialize with 1 ref so it is never deleted
|
|
};
|
|
|
|
typedef StringHandleTemplate<char, CharStringRoutines> StringHandleA;
|
|
typedef StringHandleTemplate<WCHAR, WCHARStringRoutines> StringHandleW;
|
|
|
|
#define _BITS_SMARTPTR_H
|
|
#endif //_BITS_SMARTPTR_H
|