934 lines
23 KiB
C++
934 lines
23 KiB
C++
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// File:
|
||
// ole2int.h
|
||
//
|
||
// Contents:
|
||
// This is the internal compound document header file that all
|
||
// implementations in the linking and embedding code include.
|
||
//
|
||
// Classes:
|
||
//
|
||
// Functions:
|
||
//
|
||
// History:
|
||
// 20-Jan-95 t-ScottH add CThreadCheck::Dump method (_DEBUG only)
|
||
// 09-Jan-95 t-scotth changed macro VDATETHREAD to accept a
|
||
// pointer
|
||
// 19-Apr-94 alexgo renamed global clipboard formats to
|
||
// Cairo conventions
|
||
// 24-Jan-94 alexgo first pass converting to Cairo style
|
||
// memory allocation
|
||
// 01/13/93 - alexgo - temporarily disabled _DEBUG for Chicago
|
||
// 12/30/93 - ChrisWe - define _DEBUG #if DBG==1 so that asserts
|
||
// are included; got rid of some previously #ifdef NEVER
|
||
// code; added proper file prolog
|
||
// 12/27/93 - ErikGav - changed lstr* to wcs* on Win32
|
||
// 12/17/93 - ChrisWe - added first pass at GlobalAlloc debugging
|
||
// macros
|
||
// 12/08/93 - ChrisWe - made error assert message strings constant;
|
||
// formatting changes
|
||
// 12/07/93 - ChrisWe - removed obsolete names for memory arenas;
|
||
// did some minor formatting; removed obsolete DBCS stuff
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
/*
|
||
* This is the internal ole2 header, which means it contains those
|
||
* interfaces which might eventually be exposed to the outside
|
||
* and which will be exposed to our implementations. We don't want
|
||
* to expose these now, so I have put them in a separate file.
|
||
*/
|
||
|
||
#ifndef _LE2INT_H_
|
||
#define _LE2INT_H_
|
||
|
||
//
|
||
// Prevent lego errors under Chicago.
|
||
//
|
||
#if defined(_CHICAGO_)
|
||
#define _CTYPE_DISABLE_MACROS
|
||
#endif
|
||
|
||
#ifndef _CHICAGO_
|
||
// For TLS on Nt, we use a reserved DWORD in the TEB directly. We need to
|
||
// include these files in order to get the macro NtCurrentTeb. These must
|
||
// be included before windows.h
|
||
extern "C"
|
||
{
|
||
#include <nt.h> // NT_PRODUCT_TYPE
|
||
#include <ntdef.h> // NT_PRODUCT_TYPE
|
||
#include <ntrtl.h> // NT_PRODUCT_TYPE
|
||
#include <nturtl.h> // NT_PRODUCT_TYPE
|
||
#include <windef.h> // NT_PRODUCT_TYPE
|
||
#include <winbase.h> // NT_PRODUCT_TYPE
|
||
}
|
||
#endif // _CHICAGO_
|
||
|
||
|
||
// ------------------------------------
|
||
// system includes
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <stddef.h>
|
||
|
||
#ifdef WIN32
|
||
# include <wchar.h>
|
||
#else
|
||
# include <ctype.h>
|
||
#endif
|
||
|
||
// we need to turn on the validation code in the ole library for
|
||
// Cairo/Daytona/Chicago debug builds, which was keyed off _DEBUG
|
||
// in the win16 code. It appears we need this before any other files
|
||
// are included so that debug only declarations in ole2.h/compobj.h
|
||
// get processed.
|
||
#if DBG==1
|
||
# ifndef _DEBUG
|
||
# define _DEBUG
|
||
# endif
|
||
#endif
|
||
|
||
#ifndef _MAC
|
||
# include <windows.h>
|
||
# include <malloc.h>
|
||
# include <shellapi.h>
|
||
#else
|
||
//#include <mac.h>
|
||
#endif // _MAC
|
||
|
||
//
|
||
// Debug support
|
||
//
|
||
|
||
# include <debnot.h>
|
||
|
||
DECLARE_DEBUG(LE)
|
||
DECLARE_DEBUG(Ref)
|
||
DECLARE_DEBUG(DD)
|
||
|
||
#if DBG==1
|
||
|
||
#define LEDebugOut(x) LEInlineDebugOut x
|
||
#define RefDebugOut(x) RefInlineDebugOut x
|
||
#define DDDebugOut(x) DDInlineDebugOut x
|
||
|
||
#else
|
||
|
||
#define LEDebugOut(x) NULL
|
||
#define RefDebugOut(x) NULL
|
||
#define DDDebugOut(x) NULL
|
||
|
||
#endif // DBG
|
||
|
||
#include <tls.h>
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Function: LEERROR (macro)
|
||
//
|
||
// Synopsis: prints out an error message if [cond] is TRUE, along with
|
||
// the file and line information
|
||
//
|
||
// Effects:
|
||
//
|
||
// Arguments: [cond] -- condition to test against
|
||
// [szError] -- string to print out
|
||
//
|
||
// Requires:
|
||
//
|
||
// Returns:
|
||
//
|
||
// Signals:
|
||
//
|
||
// Modifies:
|
||
//
|
||
// Algorithm:
|
||
//
|
||
// History: dd-mmm-yy Author Comment
|
||
// 18-Apr-94 alexgo author
|
||
//
|
||
// Notes: Only present in DEBUG builds
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
#if DBG==1
|
||
|
||
#define LEERROR( cond, szError ) if( cond ) {\
|
||
LEDebugOut((DEB_ERROR, "ERROR!: %s (%s %d)\n", szError, __FILE__, \
|
||
__LINE__)); }
|
||
|
||
#else
|
||
|
||
#define LEERROR( cond, szError )
|
||
|
||
#endif //!DBG
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Function: LEWARN (macro)
|
||
//
|
||
// Synopsis: prints out a warning message if [cond] is TRUE, along with
|
||
// the file and line information
|
||
//
|
||
// Effects:
|
||
//
|
||
// Arguments: [cond] -- condition to test against
|
||
// [szWarn] -- string to print out
|
||
//
|
||
// Requires:
|
||
//
|
||
// Returns:
|
||
//
|
||
// Signals:
|
||
//
|
||
// Modifies:
|
||
//
|
||
// Algorithm:
|
||
//
|
||
// History: dd-mmm-yy Author Comment
|
||
// 18-Apr-94 alexgo author
|
||
//
|
||
// Notes: Only present in DEBUG builds
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
#if DBG==1
|
||
|
||
#define LEWARN( cond, szWarn ) if( cond ) {\
|
||
LEDebugOut((DEB_WARN, "WARNING!: %s (%s %d)\n", szWarn, __FILE__, \
|
||
__LINE__)); }
|
||
|
||
#else
|
||
|
||
#define LEWARN( cond, szWarn )
|
||
|
||
#endif //!DBG
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Function: LEVERIFY (macro)
|
||
//
|
||
// Synopsis: prints out a warning message if [cond] is FALSE, along with
|
||
// the file and line information. In non-debug builds, the
|
||
// condition IS still evaluated/executed.
|
||
//
|
||
// Effects:
|
||
//
|
||
// Arguments: [cond] -- condition to test for (intended to be true)
|
||
//
|
||
// Requires:
|
||
//
|
||
// Returns:
|
||
//
|
||
// Signals:
|
||
//
|
||
// Modifies:
|
||
//
|
||
// Algorithm:
|
||
//
|
||
// History: dd-mmm-yy Author Comment
|
||
// 30-Aug-94 davepl author
|
||
//
|
||
// Notes: Warns only in DEBUG builds, executes in all builds
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
#if DBG==1
|
||
|
||
#define LEVERIFY( cond ) ( (cond) ? \
|
||
(void) NULL : \
|
||
LEDebugOut((DEB_WARN, "VERIFY FAILED: %s (%s %d)\n", #cond, __FILE__, __LINE__)) \
|
||
)
|
||
|
||
#else
|
||
|
||
#define LEVERIFY( cond ) (void) (cond)
|
||
|
||
#endif //!DBG
|
||
|
||
|
||
#ifdef WIN32
|
||
|
||
# define __loadds // Not used
|
||
# define UnlockData(ds) // Not used
|
||
|
||
# define _fmalloc malloc
|
||
# define _frealloc realloc
|
||
# define _ffree free
|
||
|
||
#endif // WIN32
|
||
|
||
#ifdef WIN32
|
||
|
||
# define _xmemset memset
|
||
# define _xmemcpy memcpy
|
||
# define _xmemcmp memcmp
|
||
# define _xmemmove memmove
|
||
|
||
#else
|
||
|
||
# define _xmemset _fmemset
|
||
# define _xmemcpy _fmemcpy
|
||
# define _xmemcmp _fmemcmp
|
||
# define _xmemmove _fmemmove
|
||
|
||
#endif // WIN32
|
||
|
||
|
||
#ifdef WIN32
|
||
|
||
# define EXPORT
|
||
|
||
#else
|
||
|
||
# define EXPORT __export
|
||
|
||
#endif
|
||
|
||
|
||
// ------------------------------------
|
||
// public includes
|
||
#include <ole2.h>
|
||
#include <ole2sp.h>
|
||
#include <ole2com.h>
|
||
// ------------------------------------
|
||
// internal includes
|
||
#include <utils.h>
|
||
#include <olecoll.h>
|
||
#include <valid.h>
|
||
#include <map_kv.h>
|
||
#include <privguid.h>
|
||
#include <memapi.hxx>
|
||
|
||
/* Exported CLSIDs.. */
|
||
// REVIEW, why not just change these to be correct?
|
||
#define CLSID_StaticMetafile CLSID_Picture_Metafile
|
||
#define CLSID_StaticDib CLSID_Picture_Dib
|
||
|
||
|
||
|
||
#ifdef _MAC
|
||
#define BITMAP_TO_DIB(foretc)
|
||
#else
|
||
#define BITMAP_TO_DIB(foretc) \
|
||
if (foretc.cfFormat == CF_BITMAP) {\
|
||
foretc.cfFormat = CF_DIB;\
|
||
foretc.tymed = TYMED_HGLOBAL;\
|
||
}
|
||
#endif // _MAC
|
||
|
||
|
||
// NOTE!!!
|
||
//
|
||
// If a member is added to the aspect, tymed, or advf enumerations,
|
||
// these values MUST be updated accordingly!!
|
||
|
||
#define MAX_VALID_ASPECT DVASPECT_DOCPRINT
|
||
#define MAX_VALID_TYMED TYMED_ENHMF
|
||
#define MAX_VALID_ADVF ADVF_DATAONSTOP
|
||
|
||
// This creates a mask of the valid ADVF bits:
|
||
#define MASK_VALID_ADVF ((MAX_VALID_ADVF << 1) - 1)
|
||
|
||
// #include "pres.h"
|
||
|
||
#define VERIFY_ASPECT_SINGLE(dwAsp) {\
|
||
if (!(dwAsp && !(dwAsp & (dwAsp-1)) && (dwAsp <= MAX_VALID_ASPECT))) {\
|
||
LEDebugOut((DEB_WARN, "More than 1 aspect is specified"));\
|
||
return ResultFromScode(DV_E_DVASPECT);\
|
||
}\
|
||
}
|
||
|
||
|
||
#define VERIFY_TYMED_SINGLE(tymed) {\
|
||
if (!(tymed && !(tymed & (tymed-1)) && (tymed <= MAX_VALID_TYMED))) \
|
||
return ResultFromScode(DV_E_TYMED); \
|
||
}
|
||
|
||
// Legal formats for clipformat (and thus, cache nodes)
|
||
// CF_METAFILEPICT && TYMED_MFPICT
|
||
// CF_BITMAP && TYMED_GDI
|
||
// CF_DIB && TYMED_HGLOBAL
|
||
// CF_other && TYMED_HGLOBAL
|
||
|
||
#define VERIFY_TYMED_VALID_FOR_CLIPFORMAT(pfetc) {\
|
||
if ((pfetc->cfFormat==CF_METAFILEPICT && !(pfetc->tymed & TYMED_MFPICT))\
|
||
|| (pfetc->cfFormat==CF_ENHMETAFILE && !(pfetc->tymed & TYMED_ENHMF))\
|
||
|| (pfetc->cfFormat==CF_BITMAP && !(pfetc->tymed & TYMED_GDI))\
|
||
|| (pfetc->cfFormat==CF_DIB && !(pfetc->tymed & TYMED_HGLOBAL))\
|
||
|| (pfetc->cfFormat!=CF_METAFILEPICT && \
|
||
pfetc->cfFormat!=CF_BITMAP && \
|
||
pfetc->cfFormat!=CF_DIB && \
|
||
pfetc->cfFormat!=CF_ENHMETAFILE && \
|
||
!(pfetc->tymed & TYMED_HGLOBAL)))\
|
||
return ResultFromScode(DV_E_TYMED); \
|
||
}
|
||
|
||
#define VERIFY_TYMED_SINGLE_VALID_FOR_CLIPFORMAT(pfetc) \
|
||
{ \
|
||
if (pfetc->cfFormat==CF_METAFILEPICT && pfetc->tymed != TYMED_MFPICT) \
|
||
return ResultFromScode(DV_E_TYMED); \
|
||
\
|
||
if (pfetc->cfFormat==CF_ENHMETAFILE && pfetc->tymed != TYMED_ENHMF) \
|
||
return ResultFromScode(DV_E_TYMED); \
|
||
\
|
||
if (pfetc->cfFormat==CF_BITMAP && pfetc->tymed != TYMED_GDI) \
|
||
return ResultFromScode(DV_E_TYMED); \
|
||
\
|
||
if (pfetc->cfFormat==CF_DIB && pfetc->tymed != TYMED_HGLOBAL) \
|
||
return ResultFromScode(DV_E_TYMED); \
|
||
\
|
||
if (pfetc->cfFormat != CF_METAFILEPICT) \
|
||
if (pfetc->cfFormat != CF_BITMAP) \
|
||
if (pfetc->cfFormat != CF_DIB) \
|
||
if (pfetc->cfFormat != CF_ENHMETAFILE) \
|
||
if (pfetc->tymed != TYMED_HGLOBAL) \
|
||
return ResultFromScode(DV_E_TYMED); \
|
||
}
|
||
|
||
// This was the original code...
|
||
|
||
/*
|
||
#define VERIFY_TYMED_SINGLE_VALID_FOR_CLIPFORMAT(pfetc) {\
|
||
if ((pfetc->cfFormat==CF_METAFILEPICT && pfetc->tymed!=TYMED_MFPICT)\
|
||
|| ( (pfetc->cfFormat==CF_BITMAP || \
|
||
pfetc->cfFormat == CF_DIB ) \
|
||
&& pfetc->tymed!=TYMED_GDI)\
|
||
|| (pfetc->cfFormat!=CF_METAFILEPICT && \
|
||
pfetc->cfFormat!=CF_BITMAP && \
|
||
pfetc->cfFormat!=CF_DIB && \
|
||
pfetc->tymed!=TYMED_HGLOBAL)) \
|
||
return ResultFromScode(DV_E_TYMED); \
|
||
}
|
||
*/
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function:
|
||
// CreateObjectDescriptor, static
|
||
//
|
||
// Synopsis:
|
||
// Creates and initializes an OBJECTDESCRIPTOR from the given
|
||
// parameters
|
||
//
|
||
// Arguments:
|
||
// [clsid] -- the class ID of the object being transferred
|
||
// [dwAspect] -- the display aspect drawn by the source of the
|
||
// transfer
|
||
// [psizel] -- pointer to the size of the object
|
||
// [ppointl] -- pointer to the mouse offset in the object that
|
||
// initiated a drag-drop transfer
|
||
// [dwStatus] -- the OLEMISC status flags for the object
|
||
// being transferred
|
||
// [lpszFullUserTypeName] -- the full user type name of the
|
||
// object being transferred
|
||
// [lpszSrcOfCopy] -- a human readable name for the object
|
||
// being transferred
|
||
//
|
||
// Returns:
|
||
// If successful, A handle to the new OBJECTDESCRIPTOR; otherwise
|
||
// NULL.
|
||
//
|
||
// Notes:
|
||
// REVIEW, this seems generally useful for anyone using the
|
||
// clipboard, or drag-drop; perhaps it should be exported.
|
||
//
|
||
// History:
|
||
// 12/07/93 - ChrisWe - file inspection and cleanup
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
INTERNAL_(HGLOBAL) CreateObjectDescriptor(CLSID clsid, DWORD dwAspect,
|
||
const SIZEL FAR *psizel, const POINTL FAR *ppointl,
|
||
DWORD dwStatus, LPOLESTR lpszFullUserTypeName,
|
||
LPOLESTR lpszSrcOfCopy);
|
||
|
||
|
||
INTERNAL_(HRESULT) CheckTymedCFCombination(LPFORMATETC pfetc);
|
||
|
||
/*
|
||
#define VERIFY_ASPECT_SINGLE(dwAsp) {\
|
||
if (!(dwAsp && !(dwAsp & (dwAsp-1)) && (dwAsp <= MAX_VALID_ASPECT))) {\
|
||
AssertSz(FALSE, "More than 1 aspect is specified");\
|
||
return ResultFromScode(DV_E_DVASPECT);\
|
||
}\
|
||
}
|
||
*/
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function:
|
||
// VerifyAspectSingle (Internal Inline)
|
||
//
|
||
// Synopsis:
|
||
// Verifies that exactly one bit is set in the aspect, and that
|
||
// it is one of the known aspect bits.
|
||
//
|
||
// Returns:
|
||
// S_OK For a valid aspect
|
||
// DV_E_ASPECT For an invalid aspect
|
||
//
|
||
// Notes:
|
||
// The (0 == (dwAsp & (dwAsp - 1))) test is an efficient means
|
||
// for testing that exactly at most bit is set in dwAsp, once it
|
||
// is known that dwAsp is nonzero.
|
||
//
|
||
// History:
|
||
// 01/07/94 DavePl Created
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
inline HRESULT VerifyAspectSingle(DWORD dwAsp)
|
||
{
|
||
// Ensure at least one bit is set
|
||
|
||
if (dwAsp)
|
||
{
|
||
// Ensure at most one bit is set
|
||
|
||
if (0 == (dwAsp & (dwAsp-1)))
|
||
{
|
||
// Ensure that one bit is valid
|
||
|
||
if (MAX_VALID_ASPECT >= dwAsp)
|
||
{
|
||
return S_OK;
|
||
}
|
||
}
|
||
}
|
||
|
||
LEDebugOut((DEB_WARN,"WARNING: Invalid Aspect DWORD -> %0X\n", dwAsp));
|
||
|
||
return DV_E_DVASPECT;
|
||
}
|
||
|
||
|
||
/*
|
||
#define VERIFY_TYMED_SINGLE(tymed) {\
|
||
if (!(tymed && !(tymed & (tymed-1)) && (tymed <= MAX_VALID_TYMED))) \
|
||
return ResultFromScode(DV_E_TYMED); \
|
||
}
|
||
*/
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function:
|
||
// VerifyTymedSingle (Internal Inline)
|
||
//
|
||
// Synopsis:
|
||
// Verifies that exactly one bit is set in the tymed, and that
|
||
// it is one of the known tymed bits.
|
||
//
|
||
// Returns:
|
||
// S_OK For a valid aspect
|
||
// DV_E_ASPECT For an invalid aspect
|
||
//
|
||
// Notes:
|
||
// The (0 == (dwAsp & (dwAsp - 1))) test is an efficient means
|
||
// for testing that exactly at most bit is set in dwTymed, once it
|
||
// is known that dwTymed is nonzero.
|
||
//
|
||
// History:
|
||
// 01/07/94 DavePl Created
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
inline HRESULT VerifyTymedSingle(DWORD dwTymed)
|
||
{
|
||
// Ensure that at least one bit is set
|
||
|
||
if (dwTymed)
|
||
{
|
||
// Ensure that at most one bit is set
|
||
|
||
if (0 == (dwTymed & (dwTymed - 1)))
|
||
{
|
||
// Ensure that the one set bit is a valid one
|
||
|
||
if (MAX_VALID_TYMED >= dwTymed)
|
||
{
|
||
return S_OK;
|
||
}
|
||
}
|
||
}
|
||
|
||
LEDebugOut((DEB_WARN,"WARNING: Invalid Tymed DWORD -> %0X\n", dwTymed));
|
||
|
||
return DV_E_TYMED;
|
||
}
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Class: CSafeRefCount
|
||
//
|
||
// Purpose: A class that implements reference counting rules for objects.
|
||
// It keeps track of reference count and zombie state.
|
||
// It helps object manage their liveness properly.
|
||
//
|
||
// History: dd-mmm-yy Author Comment
|
||
// 16-Jan-97 Gopalk Simplified and Rewritten to handle
|
||
// aggregation
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
class CSafeRefCount : public CPrivAlloc
|
||
{
|
||
public:
|
||
// Constructor
|
||
CSafeRefCount(IUnknown *pUnkOuter) {
|
||
m_cRefs = 0;
|
||
m_fInDelete = FALSE;
|
||
m_pUnkOuter = pUnkOuter;
|
||
#if DBG==1
|
||
m_cNestCount = 0;
|
||
#endif
|
||
}
|
||
|
||
// Destructor. It has to be virtual so that delete this will
|
||
// despatched to the right object
|
||
virtual ~CSafeRefCount() {
|
||
Win4Assert(!m_cRefs && !m_cNestCount && m_fInDelete);
|
||
}
|
||
|
||
// Reference count methods
|
||
ULONG SafeAddRef() {
|
||
return InterlockedIncrement((LONG *)& m_cRefs);
|
||
}
|
||
ULONG SafeRelease();
|
||
|
||
// Nest count methods
|
||
void IncrementNestCount() {
|
||
#if DBG==1
|
||
InterlockedIncrement((LONG *) &m_cNestCount);
|
||
#endif
|
||
if(m_pUnkOuter)
|
||
m_pUnkOuter->AddRef();
|
||
else
|
||
SafeAddRef();
|
||
|
||
return;
|
||
}
|
||
void DecrementNestCount() {
|
||
#if DBG==1
|
||
InterlockedDecrement((LONG *) &m_cNestCount);
|
||
Win4Assert((LONG) m_cNestCount >= 0);
|
||
#endif
|
||
if(m_pUnkOuter)
|
||
m_pUnkOuter->Release();
|
||
else
|
||
SafeRelease();
|
||
|
||
return;
|
||
}
|
||
|
||
// State methods
|
||
BOOL IsZombie() {
|
||
return m_fInDelete;
|
||
}
|
||
|
||
// Other useful methods
|
||
IUnknown *GetPUnkOuter() {
|
||
return m_pUnkOuter;
|
||
}
|
||
ULONG GetRefCount(void) {
|
||
return m_cRefs;
|
||
}
|
||
#if DBG==1
|
||
ULONG GetNestCount(void) {
|
||
return m_cNestCount;
|
||
}
|
||
#endif
|
||
|
||
private:
|
||
ULONG m_cRefs;
|
||
BOOL m_fInDelete;
|
||
IUnknown *m_pUnkOuter;
|
||
#if DBG==1
|
||
ULONG m_cNestCount;
|
||
#endif
|
||
};
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Class: CRefExportCount
|
||
//
|
||
// Purpose: A class that implements reference counting rules for server
|
||
// objects that export their nested objects on behalf of their
|
||
// clients like DEFHANDLER abd CACHE. It keeps track of
|
||
// reference count, export count, zombie state, etc.
|
||
// It helps object manage their shutdown logic properly.
|
||
//
|
||
// History: dd-mmm-yy Author Comment
|
||
// 16-Jan-97 Gopalk Creation
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
class CRefExportCount : public CPrivAlloc
|
||
{
|
||
public:
|
||
// Constructor
|
||
CRefExportCount(IUnknown *pUnkOuter) {
|
||
m_cRefs = 0;
|
||
m_cExportCount = 0;
|
||
m_IsZombie = FALSE;
|
||
m_Status = ALIVE;
|
||
m_pUnkOuter = pUnkOuter;
|
||
#if DBG==1
|
||
m_cNestCount = 0;
|
||
#endif
|
||
}
|
||
|
||
// Destructor. It has to be virtual so that delete this will
|
||
// despatched to the right object
|
||
virtual ~CRefExportCount() {
|
||
Win4Assert(!m_cRefs && !m_cNestCount && !m_cExportCount &&
|
||
m_IsZombie && m_Status==DEAD);
|
||
}
|
||
|
||
// Reference count methods
|
||
ULONG SafeAddRef() {
|
||
return InterlockedIncrement((LONG *)& m_cRefs);
|
||
}
|
||
ULONG SafeRelease();
|
||
|
||
// Nest count methods
|
||
void IncrementNestCount() {
|
||
#if DBG==1
|
||
InterlockedIncrement((LONG *) &m_cNestCount);
|
||
#endif
|
||
if(m_pUnkOuter)
|
||
m_pUnkOuter->AddRef();
|
||
else
|
||
SafeAddRef();
|
||
|
||
return;
|
||
}
|
||
void DecrementNestCount() {
|
||
#if DBG==1
|
||
InterlockedDecrement((LONG *) &m_cNestCount);
|
||
Win4Assert((LONG) m_cNestCount >= 0);
|
||
#endif
|
||
if(m_pUnkOuter)
|
||
m_pUnkOuter->Release();
|
||
else
|
||
SafeRelease();
|
||
|
||
return;
|
||
}
|
||
|
||
// Methods used by exported nested objects
|
||
ULONG IncrementExportCount() {
|
||
return InterlockedIncrement((LONG *) &m_cExportCount);
|
||
}
|
||
ULONG DecrementExportCount();
|
||
|
||
// State methods
|
||
BOOL IsZombie() {
|
||
return m_IsZombie;
|
||
}
|
||
BOOL IsExported() {
|
||
return m_cExportCount>0;
|
||
}
|
||
|
||
// Other useful methods
|
||
IUnknown *GetPUnkOuter() {
|
||
return m_pUnkOuter;
|
||
}
|
||
ULONG GetRefCount(void) {
|
||
return m_cRefs;
|
||
}
|
||
ULONG GetExportCount(void) {
|
||
return m_cExportCount;
|
||
}
|
||
#if DBG==1
|
||
ULONG GetNestCount(void) {
|
||
return m_cNestCount;
|
||
}
|
||
#endif
|
||
|
||
private:
|
||
// Cleanup function which is invoked when the object transistions
|
||
// into zombie state. It is virtual so that the correct cleanup
|
||
// function is invoked
|
||
virtual void CleanupFn(void) {
|
||
return;
|
||
}
|
||
|
||
// Tokens used
|
||
enum tagTokens {
|
||
ALIVE = 0,
|
||
KILL = 1,
|
||
DEAD = 2
|
||
};
|
||
|
||
// Member variables
|
||
ULONG m_cRefs;
|
||
ULONG m_cExportCount;
|
||
ULONG m_IsZombie;
|
||
ULONG m_Status;
|
||
IUnknown *m_pUnkOuter;
|
||
#if DBG==1
|
||
ULONG m_cNestCount;
|
||
#endif
|
||
};
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Class: CStabilize
|
||
//
|
||
// Purpose: An instance of this class should be allocated on the
|
||
// stack of every object method that makes an outgoing call.
|
||
//
|
||
// History: dd-mmm-yy Author Comment
|
||
// 16-Jan-97 Gopalk Simplified and Rewritten to handle
|
||
// aggregation
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
class CStabilize
|
||
{
|
||
public:
|
||
// Constructor
|
||
CStabilize(CSafeRefCount *pSafeRefCount) {
|
||
m_pSafeRefCount = pSafeRefCount;
|
||
pSafeRefCount->IncrementNestCount();
|
||
}
|
||
// Destructor
|
||
~CStabilize() {
|
||
m_pSafeRefCount->DecrementNestCount();
|
||
}
|
||
|
||
private:
|
||
CSafeRefCount *m_pSafeRefCount;
|
||
};
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Class: CRefStabilize
|
||
//
|
||
// Purpose: An instance of this class should be allocated on the
|
||
// stack of every object method that makes an outgoing call.
|
||
//
|
||
// History: dd-mmm-yy Author Comment
|
||
// 16-Jan-97 Gopalk Simplified and Rewritten to handle
|
||
// aggregation
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
class CRefStabilize
|
||
{
|
||
public:
|
||
// Constructor
|
||
CRefStabilize(CRefExportCount *pRefExportCount) {
|
||
m_pRefExportCount = pRefExportCount;
|
||
pRefExportCount->IncrementNestCount();
|
||
}
|
||
// Destructor
|
||
~CRefStabilize() {
|
||
m_pRefExportCount->DecrementNestCount();
|
||
}
|
||
|
||
private:
|
||
CRefExportCount *m_pRefExportCount;
|
||
};
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Class: CThreadCheck
|
||
//
|
||
// Purpose: ensures that an object is called on the correct thread
|
||
//
|
||
// Interface:
|
||
//
|
||
// History: dd-mmm-yy Author Comment
|
||
// 30-Jan-95 t-ScottH add Dump method to CThreadCheck class
|
||
// (_DEBUG only)
|
||
// 21-Nov-94 alexgo author
|
||
//
|
||
// Notes: To use this class, an object should simply publicly
|
||
// inherit CThreadCheck. The VDATETHREAD macro can then be
|
||
// used to check the thread id at each entry point.
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
class CThreadCheck
|
||
{
|
||
public:
|
||
inline CThreadCheck();
|
||
BOOL VerifyThreadId(); // in utils.cpp
|
||
#ifdef _DEBUG
|
||
HRESULT Dump(char **ppszDumpOA, ULONG ulFlag, int nIndentLevel); // utils.cpp
|
||
#endif //_DEBUG
|
||
|
||
private:
|
||
DWORD m_tid;
|
||
};
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Member: CThreadCheck::CThreadCheck
|
||
//
|
||
// Synopsis: stores the current thread id
|
||
//
|
||
// Effects:
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Requires:
|
||
//
|
||
// Returns: void
|
||
//
|
||
// Signals:
|
||
//
|
||
// Modifies:
|
||
//
|
||
// Derivation:
|
||
//
|
||
// Algorithm:
|
||
//
|
||
// History: dd-mmm-yy Author Comment
|
||
// 21-Nov-94 alexgo author
|
||
//
|
||
// Notes:
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
inline CThreadCheck::CThreadCheck( void )
|
||
{
|
||
m_tid = GetCurrentThreadId();
|
||
|
||
LEWARN(!m_tid, "GetCurrentThreadId failed!!");
|
||
}
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Function: VDATETHREAD (macro)
|
||
//
|
||
// Synopsis: makes sure the correct thread is called
|
||
//
|
||
// Effects:
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Requires: the calling class must inherit from CThreadCheck
|
||
//
|
||
// Returns: RPC_E_WRONG_THREAD if called on the wrong thread
|
||
//
|
||
// Signals:
|
||
//
|
||
// Modifies:
|
||
//
|
||
// Algorithm:
|
||
//
|
||
// History: dd-mmm-yy Author Comment
|
||
// 09-Jan-95 t-ScottH give VDATETHREAD an argument
|
||
// 21-Nov-94 alexgo author
|
||
//
|
||
// Notes: THIS MACRO FUNCTIONS IN RETAIL BUILDS TOO!!!
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
|
||
#define VDATETHREAD(pObject) if( !( pObject->VerifyThreadId() ) ) { return RPC_E_WRONG_THREAD; }
|
||
|
||
// utility macros.
|
||
|
||
#define LONG_ABS(x) ((x) < 0 ? -(x) : (x))
|
||
|
||
|
||
#endif // _LE2INT_H_
|
||
|