//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1992, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of TGdiObject, abstract class for GDI objects that can be
/// selected into TDCs
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/gdiobjec.h>
#if defined(BI_MULTI_THREAD_RTL)
#include <owl/thread.h>
#endif
#include <owl/template.h>
using namespace std;
namespace owl {
OWL_DIAGINFO;
DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlGDI, 1, 0);
// General GDI diagnostic group
DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlGDIOrphan, 1, 0);
// Orphan control tracing group
//
// TGdiObject's internal orphan control object, container and member functions
//
struct TObjInfo {
HANDLE Handle;
TGdiObject::TType Type;
int RefCount;
TObjInfo() : Handle(0), Type(TGdiObject::None), RefCount(0)
{}
TObjInfo(HANDLE handle) : Handle(handle)
{}
TObjInfo(HANDLE handle, TGdiObject::TType type, int ref)
: Handle(handle), Type(type), RefCount(ref)
{}
~TObjInfo()
{}
bool operator ==(const TObjInfo& other) const {
return other.Handle == Handle;
}
bool operator <(const TObjInfo& other) const {
return other.Handle < Handle;
}
};
typedef TSortedObjectArray<TObjInfo> TObjInfoBag;
static TObjInfoBag* __ObjInfoBag = 0;
#if defined(BI_MULTI_THREAD_RTL)
static TMRSWSection* __ObjInfoBagLock = 0;
#endif
#if defined(BI_MULTI_THREAD_RTL) //ObjInfoBag().Lock
#define LOCKOBJECTBAG(s) TMRSWSection::TLock __lock(*__ObjInfoBagLock,s)
#else
#define LOCKOBJECTBAG(s)
#endif
//static TObjInfoBag* ObjInfoBag;
#if defined(__TRACE)
static const LPCTSTR ObjTypeStr[] = {
_T("?"), _T("Pen"), _T("Brush"), _T("Font"), _T("Palette"),
_T("Bitmap"), 0
};
#endif
//
static void createObjInfoBag()
{
static LONG createObjInfo = -1;
if(__ObjInfoBag)
return;
if(::InterlockedIncrement(&createObjInfo)==0){
::InterlockedIncrement(&createObjInfo);
__ObjInfoBag = new TObjInfoBag;
#if defined(BI_MULTI_THREAD_RTL)
__ObjInfoBagLock = new TMRSWSection;
#endif
createObjInfo = -1;
}
}
//
static void destroyObjInfoBag()
{
static LONG destroyObjInfo = -1;
if(__ObjInfoBag==0 || __ObjInfoBag->Size()>0)
return;
if(::InterlockedIncrement(&destroyObjInfo)==0){
::InterlockedIncrement(&destroyObjInfo);
delete __ObjInfoBag;
#if defined(BI_MULTI_THREAD_RTL)
delete __ObjInfoBagLock;
#endif
__ObjInfoBag = 0;
destroyObjInfo = -1;
}
}
//
/// Searches for the given object handle.
/// \returns If found, the object's type and reference count are returned in the specified TObjInfo
/// object. RefFind returns 0 if no match is found.
//
TObjInfo*
TGdiObject::RefFind(HANDLE handle)
{
if (handle && __ObjInfoBag)
{
LOCKOBJECTBAG(true);
const auto pos = __ObjInfoBag->Find(TObjInfo(handle));
if (pos != __ObjInfoBag->NPOS)
return &((*__ObjInfoBag)[pos]);
}
return nullptr;
}
//
/// RefAdd adds a reference entry for the object with the given handle and type.
/// If the table already has a matching entry, no action is taken, otherwise the reference count is
/// set to 1.
//
void
TGdiObject::RefAdd(HANDLE handle, TGdiObject::TType type)
{
createObjInfoBag();
#if !defined(NO_GDI_SHARE_HANDLES)
if (handle) {
TObjInfo* member = RefFind(handle);
if (member)
member->RefCount++;
else {
LOCKOBJECTBAG(false);
__ObjInfoBag->Add(TObjInfo(handle, type, 1));
}
}
#else
if (handle && !RefFind(handle)){
LOCKOBJECTBAG(false);
__ObjInfoBag->Add(TObjInfo(handle, type, 1));
}
#endif
}
//
/// Removes the reference entry to the object with the given handle.
/// If the given handle is not found, no action is taken.
//
void
TGdiObject::RefRemove(HANDLE handle)
{
if(!__ObjInfoBag)
return;
{
LOCKOBJECTBAG(false);
__ObjInfoBag->DestroyItem(TObjInfo(handle));
}
destroyObjInfoBag();
}
//
/// Increments by 1 the reference count of the object associated with the given handle.
//
void
TGdiObject::RefInc(HANDLE handle)
{
createObjInfoBag();
TObjInfo* member = RefFind(handle);
if (member)
{
member->RefCount++;
}
}
//
/// Decrements this object's reference count by 1 and deletes the object when the reference count
/// reaches zero.
///
/// A warning is issued if the deletion was supposed to happen but didn't. Likewise, a warning is
/// issued if the deletion wasn't supposed to happen but did. The deleted object is also detached
/// from the ObjInfoBag table.
///
/// You can vary the normal deletion strategy by setting wantDelete to true or false.
//
void
TGdiObject::RefDec(HANDLE handle, bool wantDelete)
{
InUse(wantDelete);
if(!__ObjInfoBag)
return;
TObjInfo* member = RefFind(handle);
if (member) {
bool needDelete = --(member->RefCount) == 0;
#if defined(__TRACE)
if (needDelete != wantDelete) {
if (needDelete)
TRACEX(OwlGDIOrphan, 1, "Orphan" << ObjTypeStr[member->Type] <<
static_cast<void*>(member->Handle) << "Deleted");
else
TRACEX(OwlGDIOrphan, 1, ObjTypeStr[member->Type] <<
static_cast<void*>(member->Handle) << "Orphan");
}
#endif
if (needDelete) {
if (!::DeleteObject(member->Handle))
{
TXGdi::Raise(IDS_GDIDELETEFAIL, member->Handle);
}
{
LOCKOBJECTBAG(false);
__ObjInfoBag->DestroyItem(*member);
}
destroyObjInfoBag();
}
}
}
//
/// Returns this object's current reference count or -1 if the object is not found.
//
int
TGdiObject::RefCount(HANDLE handle)
{
TObjInfo* member = RefFind(handle);
if (member)
return member->RefCount;
return -1;
}
//----------------------------------------------------------------------------
//
//
//
#if defined(__TRACE) || defined(__WARN)
ostream& operator <<(ostream& os, const TGdiObject& gdiObject)
{
os << "@" << (void*)&gdiObject << " ";
os << '(';
os << typeid(gdiObject).name() << ',';
os << ')';
return os;
}
#endif
//
/// This default constructor sets Handle to 0 and ShouldDelete to true. This
/// constructor is intended for use by derived classes that must set the Handle
/// member.
//
TGdiObject::TGdiObject()
{
// Handle must be set and validated by the derived class.
TRACEX(OwlGDI, 2, "TGdiObject constructed " << *this);
}
//
/// Create a wrapper for a given GDI object.
//
/// This constructor is intended for use by derived classes only. The Handle data
/// member is "borrowed" from an existing handle given by the argument handle The
/// ShouldDelete data member defaults to false ensuring that the borrowed handle
/// will not be deleted when the object is destroyed.
//
TGdiObject::TGdiObject(HANDLE handle, TAutoDelete autoDelete)
:
TGdiBase(handle, autoDelete)
{
// Derived class must call RefAdd(Handle, type) if ShouldDelete
TRACEX(OwlGDI, 2, "TGdiObject constructed " << *this);
}
//
/// Decrement the reference count on this object.
//
/// If ShouldDelete is false no action is taken. Otherwise, the reference count for the object's
/// handle is decremented, and if it reaches zero, the handle is is deleted.
//
TGdiObject::~TGdiObject()
{
if (ShouldDelete)
RefDec(Handle, true);
TRACEX(OwlGDI, 2, "TGdiObject destructed " << *this);
}
} // OWL namespace
/* ========================================================================== */
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: Type, RefCount.
↑ V832 It's better to use '= default;' syntax instead of empty destructor body.