- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
(extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
BT game source (never mixed into CODE/). Round 1-3 state:
* 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
(BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
since 1996.
* BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
its binary-recorded line 400 exactly.
* BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
(Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
TeamScore=12 flagged [T4]).
* MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
(VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
the period compiler is the drift detector).
* Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
(per-TU verification sweep under authentic OPT.MAK flags).
* README: corrected roadmap - MECH.HPP is the capstone grown with the mech
TU reconstructions; BTREG.CPP green = the header-family milestone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
448 lines
16 KiB
C++
448 lines
16 KiB
C++
//
|
|
//----------------------------------------------------------------------------
|
|
// ObjectComponents
|
|
// (C) Copyright 1994 by Borland International, All Rights Reserved
|
|
//
|
|
// Low level OLE Utility class definitions
|
|
//----------------------------------------------------------------------------
|
|
#if !defined(OCF_OLEUTIL_H)
|
|
#define OCF_OLEUTIL_H
|
|
|
|
#if !defined(OSL_DEFS_H)
|
|
# include <osl/defs.h>
|
|
#endif
|
|
#if !defined(__CSTRING_H)
|
|
# include <cstring.h>
|
|
#endif
|
|
#if !defined(OSL_EXCEPT_H)
|
|
# include <osl/except.h>
|
|
#endif
|
|
|
|
// For 16bit Ole2, can grab the headers now if the're not included already,
|
|
// For 32bit Ole2, it is too late
|
|
//
|
|
#if defined(BI_PLAT_WIN16)
|
|
# if !defined(__OLE2_H)
|
|
# include <ole2.h>
|
|
# endif
|
|
# if !defined(__DISPATCH_H)
|
|
# include <dispatch.h>
|
|
# endif
|
|
# if !defined(__OLENLS_H)
|
|
# include <olenls.h>
|
|
# endif
|
|
#endif
|
|
#if defined(BI_PLAT_WIN32) && !defined(__OLE2_H) && !defined(_OLE2_H_)
|
|
# error INC_OLE2 must be defined before osl/defs.h is included. Include ocdefs.h first
|
|
#endif
|
|
|
|
// Force this pointers and vtable pointers far on interfaces
|
|
//
|
|
#if !defined(_ICLASS)
|
|
# if defined(__BORLANDC__)
|
|
# if defined(BI_PLAT_WIN16)
|
|
# define _ICLASS __huge
|
|
# else
|
|
# define _ICLASS
|
|
# endif
|
|
# else
|
|
# define _ICLASS FAR
|
|
# endif
|
|
#endif
|
|
|
|
#define _IFUNC STDMETHODCALLTYPE
|
|
|
|
class TRegList;
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// TXOle - OLE API related exception object
|
|
//____________________________________________________________________________
|
|
|
|
class TXOle : public TXBase {
|
|
public:
|
|
TXOle(const string& msg, HRESULT stat);
|
|
TXOle(const TXOle& src);
|
|
~TXOle();
|
|
|
|
TXOle* Clone();
|
|
void Throw();
|
|
|
|
static void Check(HRESULT stat, const char far* msg);
|
|
static void Check(HRESULT stat);
|
|
static void Throw(HRESULT stat, const char far* msg);
|
|
static void OleErrorFromCode(HRESULT stat, char far* buffer, int size);
|
|
|
|
const long Stat;
|
|
};
|
|
inline TXOle::TXOle(const string& msg, HRESULT stat)
|
|
: TXBase(msg), Stat((long)stat) {}
|
|
inline TXOle::TXOle(const TXOle& src)
|
|
: TXBase(src), Stat(src.Stat) {}
|
|
|
|
#if (__DEBUG > 0) || defined(__WARN)
|
|
# define OLECALL(func, msg) TXOle::Check(func, msg)
|
|
#else
|
|
# define OLECALL(func, msg) TXOle::Check(func)
|
|
#endif
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// TComRef - encapsulation of OLE interface pointers
|
|
//____________________________________________________________________________
|
|
|
|
template<class T> class TComRefBase {
|
|
public:
|
|
operator T far*() {return I;}
|
|
operator T far* far*() {TComRefBase::~TComRefBase(); return &I;}
|
|
int operator !() {return I==0;}
|
|
void operator delete(void* p) {((TComRefBase<T> far*)p)->I=0;}
|
|
protected:
|
|
TComRefBase(const TComRefBase<T>& i) : I(i.I) {I->AddRef();}
|
|
TComRefBase(T far* i) : I(i) {}
|
|
TComRefBase() : I(0) {}
|
|
~TComRefBase() {if (I) I->Release(); I = 0;}
|
|
T* I;
|
|
private:
|
|
void* operator new(size_t) {return 0;} // prohibit use of new
|
|
};
|
|
|
|
template<class T> class TComRef : public TComRefBase<T> {
|
|
public:
|
|
TComRef() : TComRefBase<T>() {}
|
|
TComRef(T far* iface) : TComRefBase<T>(iface) {}
|
|
TComRef(const TComRef<T>& i) : TComRefBase<T>(i) {}
|
|
T far* operator =(T far* iface) {if(I)I->Release(); return I = iface;}
|
|
T far* operator =(const TComRef<T>& i) {if(I)I->Release(); return I=i.I;}
|
|
T far* operator->() {return I;} // should throw exception if I==0
|
|
};
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// TBSTR - BASIC global string encapsulation
|
|
//____________________________________________________________________________
|
|
|
|
class TBSTR {
|
|
public:
|
|
TBSTR() : P(0) {}
|
|
TBSTR(BSTR p) : P(p) {}
|
|
~TBSTR() {::SysFreeString(P);}
|
|
BSTR operator =(BSTR p) {if(P)::SysFreeString(P); return P = p;}
|
|
TBSTR& operator =(const TBSTR& p){if(P)::SysFreeString(P);P=p.P;return *this;}
|
|
operator BSTR() {return P;}
|
|
operator BSTR far*() {if(P)::SysFreeString(P); return &P;}
|
|
int operator !() {return P==0;}
|
|
void operator ~() {if (P)::SysFreeString(P); P = 0;}
|
|
protected:
|
|
BSTR P;
|
|
private:
|
|
void* operator new(size_t) {return 0;} // prohibit use of new, delete, etc
|
|
void operator delete(void*) {}
|
|
};
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// TOleAllocator - object to initialize OLE and access memory manager
|
|
//____________________________________________________________________________
|
|
|
|
class TOleAllocator {
|
|
public:
|
|
TOleAllocator(); // gets allocator, does not initialize OLE
|
|
TOleAllocator(IMalloc* mem);// use 0 to initialize with OLE task allocator
|
|
~TOleAllocator();
|
|
void far* Alloc(unsigned long size);
|
|
void Free(void far* pv);
|
|
IMalloc* Mem;
|
|
private:
|
|
bool Initialized;
|
|
};
|
|
|
|
inline
|
|
TOleAllocator::TOleAllocator(IMalloc* mem) : Initialized(true)
|
|
{
|
|
OLECALL(OleInitialize(mem), "OleInitialize");
|
|
OLECALL(CoGetMalloc(MEMCTX_TASK, &Mem), "CoGetMalloc");
|
|
}
|
|
|
|
inline
|
|
TOleAllocator::TOleAllocator() : Initialized(false)
|
|
{
|
|
OLECALL(CoGetMalloc(MEMCTX_TASK, &Mem), "CoGetMalloc");
|
|
}
|
|
|
|
inline
|
|
TOleAllocator::~TOleAllocator()
|
|
{
|
|
if (Mem)
|
|
Mem->Release();
|
|
if (Initialized)
|
|
::OleUninitialize();
|
|
}
|
|
|
|
inline void
|
|
TOleAllocator::Free(void far* pv)
|
|
{
|
|
Mem->Free(pv);
|
|
}
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// TClassId - GUID/IID/CLSID management
|
|
//____________________________________________________________________________
|
|
|
|
class far TClassId {
|
|
public:
|
|
enum TGenerate {Generate};
|
|
TClassId(const GUID far& guid);
|
|
TClassId(const char far* idtxt);
|
|
TClassId(const TClassId& copy);
|
|
TClassId(TGenerate);
|
|
TClassId & operator =(const TClassId& copy);
|
|
TClassId(const GUID far& guid, int offset);
|
|
~TClassId();
|
|
operator GUID&();
|
|
operator const char*();
|
|
|
|
protected:
|
|
TClassId();
|
|
GUID Guid;
|
|
const char* Text;
|
|
};
|
|
|
|
inline TClassId::TClassId(const GUID far& guid) : Text(0) { Guid = guid; }
|
|
inline TClassId::TClassId(const TClassId& copy) : Guid(copy.Guid), Text(0) {}
|
|
inline TClassId::TClassId() : Text(0) {} // Guid must be set by derived class
|
|
inline TClassId::operator GUID&() { return Guid; }
|
|
inline TClassId& TClassId::operator =(const TClassId& copy)
|
|
{Guid = copy.Guid; Text=0; return *this;}
|
|
|
|
class TBaseClassId : public TClassId {
|
|
public:
|
|
TBaseClassId(TRegList& regInfo, int maxAlloc = 256);
|
|
TBaseClassId(const GUID far& guid, int maxAlloc = 256);
|
|
TBaseClassId(const char far* idtxt, int maxAlloc = 256);
|
|
TBaseClassId(TGenerate, int maxAlloc = 256);
|
|
TClassId operator [](int offset);
|
|
int AllocId();
|
|
int GetOffset(const GUID far& guid); // returns -1 if not within range
|
|
private:
|
|
int Offset; // last offset given out by AllocId(), creator reserves 0
|
|
int MaxAlloc;
|
|
};
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Fast GUID compare functions, assume that low word has already matched OK
|
|
//____________________________________________________________________________
|
|
|
|
void CmpGuid12(IUnknown* This, REFIID req, REFIID ref, void far*far* pif);
|
|
|
|
void CmpGuidOle(IUnknown* This, REFIID req, void far*far* pif);
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// TUnknown - Standard implementation of a controlling IUnknown for an object,
|
|
// to be inherited with other COM interfaces into an implementation
|
|
// class whose IUnknown implementation delegates to TUnknown::Outer.
|
|
//____________________________________________________________________________
|
|
|
|
class _ICLASS TUnknown {
|
|
public:
|
|
operator IUnknown&() {return *Outer;}
|
|
operator IUnknown*() {Outer->AddRef(); return Outer;}
|
|
IUnknown* SetOuter(IUnknown* outer = 0);
|
|
IUnknown* GetOuter() {return Outer;}
|
|
unsigned long GetRefCount();
|
|
unsigned long AdjustRefCount(int i);
|
|
IUnknown& Aggregate(TUnknown& inner); // returns outermost IUnknown
|
|
|
|
protected:
|
|
IUnknown& ThisUnknown() {return I;}
|
|
IUnknown* Outer;
|
|
TUnknown();
|
|
virtual ~TUnknown();
|
|
virtual HRESULT QueryObject(const GUID far& iid, void far* far* pif);
|
|
|
|
private:
|
|
class _ICLASS TUnknownI : public IUnknown {
|
|
public:
|
|
HRESULT _IFUNC QueryInterface(const GUID far& iid, void far*far* pif);
|
|
unsigned long _IFUNC AddRef();
|
|
unsigned long _IFUNC Release();
|
|
TUnknownI() : RefCnt(0), Inner(0) {}
|
|
~TUnknownI();
|
|
unsigned RefCnt; // object's reference count, remains 1 if aggregated
|
|
TUnknown* Inner; // chain of TUnknown-aggregated objects
|
|
private:
|
|
TUnknown& Host();
|
|
} I;
|
|
friend class TUnknownI;
|
|
};
|
|
|
|
inline IUnknown* TUnknown::SetOuter(IUnknown* outer)
|
|
{
|
|
if (outer) {
|
|
Outer = outer;
|
|
if (I.Inner)
|
|
I.Inner->SetOuter(outer);
|
|
}
|
|
return &I;
|
|
}
|
|
|
|
inline TUnknown& TUnknown::TUnknownI::Host()
|
|
{
|
|
return *(TUnknown*)((char*)this-(int)(&((TUnknown*)0)->I));
|
|
}
|
|
|
|
inline unsigned long TUnknown::AdjustRefCount(int i)
|
|
{
|
|
return (unsigned long)(I.RefCnt += i);
|
|
}
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Macros to generate COM mixin classes for use with TUnknown
|
|
// Each base class must have an inline QueryInterface wrapper defined.
|
|
//
|
|
// DECLARE_COMBASES1(classname, base) // declares support for 1 interface
|
|
// DECLARE_COMBASES2(classname, base, base) // mixes in for 2 interfaces
|
|
// .......
|
|
// DEFINE_COMBASES1(classname, base) // implements IUnknown for 1 interface
|
|
// DEFINE_COMBASES2(classname, base, base) // implements for 2 interfaces
|
|
// ......
|
|
//
|
|
// Macros to generate inline QueryInterface wrappers for interfaces/delegates
|
|
// (low GUID word may specify an explicit integer or an IID_whatever.Data1)
|
|
// For efficiency they are void functions; check result pointer for success
|
|
//
|
|
// DEFINE_QI_BASE(cls, low) // Inherited COM interface with IUnknown base
|
|
// DEFINE_QI_OLEBASE(cls, low) // Inherited OLE interface using an OLE GUID
|
|
// DEFINE_QI_DERIVED(cls, base, low) // COM interface derived from another
|
|
// DEFINE_QI_OLEDERIVED(cls, base, low) // OLE interface derived from another
|
|
// DEFINE_QI_DELEGATE(cls, member) // Inherited object with COM member
|
|
// DEFINE_QI_DELEGATE_TEST(cls, member) // Object whose COM member may be 0
|
|
// DEFINE_QI_MEMBER(name, member) // Used inside object with COM member
|
|
// DEFINE_QI_MEMBER_TEST(name, member) // Where object's COM member may be 0
|
|
//
|
|
// Macro to invoke inline QueryInterface wrappers and return if successful
|
|
// A list of these is generated by the DEFINE_COMBASESn(...) macro
|
|
//
|
|
// COMBASEQUERY(name) // Calls name_QueryInterface(), returns OK if success
|
|
//
|
|
// Macro to provide standard IUnknown implementation which forwards to Outer
|
|
// This macro is automatically invoked by the DEFINE_COMBASESn(...) macro
|
|
//
|
|
// IUNKNOWN_FORWARD(cls, outer) // cls IUnknown implementation forwards to outer
|
|
//
|
|
// Example of user-written COM class inheriting from macro-generated mixin
|
|
//
|
|
// class TSample : public classname {
|
|
// public:
|
|
// TSample(IUnknown* outer, IUnknown*far* pif) { *pif = SetOuter(outer); }
|
|
// };
|
|
//____________________________________________________________________________
|
|
|
|
#define COMBASES_D(cls, bases) \
|
|
class cls : public TUnknown, bases { \
|
|
protected: \
|
|
virtual HRESULT _IFUNC QueryInterface(const GUID far& iid, void far*far* pif); \
|
|
virtual unsigned long _IFUNC AddRef(); \
|
|
virtual unsigned long _IFUNC Release(); \
|
|
virtual HRESULT QueryObject(const GUID far& iid, void far*far* pif); \
|
|
HRESULT QueryBases(const GUID far& iid, void far*far* pif) \
|
|
{return cls::QueryObject(iid, pif);} \
|
|
}; // QueryBases() is an inline wrapper to this QueryObject() implementation
|
|
|
|
#define COMQRY1BASES(i1) protected i1
|
|
#define COMQRY2BASES(i1,i2) protected i1, COMQRY1BASES(i2)
|
|
#define COMQRY3BASES(i1,i2,i3) protected i1, COMQRY2BASES(i2,i3)
|
|
#define COMQRY4BASES(i1,i2,i3,i4) protected i1, COMQRY3BASES(i2,i3,i4)
|
|
#define COMQRY5BASES(i1,i2,i3,i4,i5) protected i1, COMQRY4BASES(i2,i3,i4,i5)
|
|
|
|
#define DECLARE_COMBASES1(cls,i1) \
|
|
COMBASES_D(cls,COMQRY1BASES(i1))
|
|
#define DECLARE_COMBASES2(cls,i1,i2) \
|
|
COMBASES_D(cls,COMQRY2BASES(i1,i2))
|
|
#define DECLARE_COMBASES3(cls,i1,i2,i3) \
|
|
COMBASES_D(cls,COMQRY3BASES(i1,i2,i3))
|
|
#define DECLARE_COMBASES4(cls,i1,i2,i3,i4) \
|
|
COMBASES_D(cls,COMQRY4BASES(i1,i2,i3,i4))
|
|
#define DECLARE_COMBASES5(cls,i1,i2,i3,i4,i5) \
|
|
COMBASES_D(cls,COMQRY5BASES(i1,i2,i3,i4,i5))
|
|
|
|
#define IUNKNOWN_FORWARD(cls, outer) \
|
|
HRESULT _IFUNC cls::QueryInterface(const GUID far& iid, void far* far* pif)\
|
|
{ return outer->QueryInterface(iid, pif); } \
|
|
unsigned long _IFUNC cls::AddRef() { return outer->AddRef(); } \
|
|
unsigned long _IFUNC cls::Release() { return outer->Release(); }
|
|
|
|
#define COMBASES_I(cls, tests) \
|
|
IUNKNOWN_FORWARD(cls, Outer) \
|
|
HRESULT cls::QueryObject(const GUID far& iid, void far*far* pif) \
|
|
{ *pif = 0; tests return ResultFromScode(E_NOINTERFACE); }
|
|
|
|
#define COMBASEQUERY(cls) \
|
|
cls##_QueryInterface(this,iid,pif); if(*pif) return NOERROR;
|
|
|
|
#define COMQRY1TEST(i1) COMBASEQUERY(i1)
|
|
#define COMQRY2TEST(i1,i2) COMBASEQUERY(i1) COMQRY1TEST(i2)
|
|
#define COMQRY3TEST(i1,i2,i3) COMBASEQUERY(i1) COMQRY2TEST(i2,i3)
|
|
#define COMQRY4TEST(i1,i2,i3,i4) COMBASEQUERY(i1) COMQRY3TEST(i2,i3,i4)
|
|
#define COMQRY5TEST(i1,i2,i3,i4,i5) COMBASEQUERY(i1) COMQRY3TEST(i2,i3,i4,i5)
|
|
|
|
#define DEFINE_COMBASES1(cls,i1) \
|
|
COMBASES_I(cls,COMQRY1TEST(i1))
|
|
#define DEFINE_COMBASES2(cls,i1,i2) \
|
|
COMBASES_I(cls,COMQRY2TEST(i1,i2))
|
|
#define DEFINE_COMBASES3(cls,i1,i2,i3) \
|
|
COMBASES_I(cls,COMQRY3TEST(i1,i2,i3))
|
|
#define DEFINE_COMBASES4(cls,i1,i2,i3,i4) \
|
|
COMBASES_I(cls,COMQRY4TEST(i1,i2,i3,i4))
|
|
#define DEFINE_COMBASES5(cls,i1,i2,i3,i4,i5) \
|
|
COMBASES_I(cls,COMQRY5TEST(i1,i2,i3,i4,i5))
|
|
|
|
#define DEFINE_QI_BASE(cls, low) \
|
|
inline void cls##_QueryInterface(cls* obj, REFIID iid, void FAR* FAR* pif) \
|
|
{if (iid.Data1==low) CmpGuid12(obj, iid, IID_##cls, pif);}
|
|
|
|
#define DEFINE_QI_OLEBASE(cls, low) \
|
|
inline void cls##_QueryInterface(cls* obj, REFIID iid, void FAR* FAR* pif) \
|
|
{if (iid.Data1==low) CmpGuidOle(obj, iid, pif);}
|
|
|
|
#define DEFINE_QI_DERIVED(cls, base, low) \
|
|
inline void cls##_QueryInterface(cls* obj, REFIID iid, void FAR* FAR* pif) \
|
|
{if (iid.Data1==low) CmpGuid12(obj, iid, IID_##cls, pif); \
|
|
else base##_QueryInterface(obj, iid, pif);}
|
|
|
|
#define DEFINE_QI_OLEDERIVED(cls, base, low) \
|
|
inline void cls##_QueryInterface(cls* obj, REFIID iid, void FAR* FAR* pif) \
|
|
{if (iid.Data1==low) CmpGuidOle(obj, iid, pif); \
|
|
else base##_QueryInterface(obj, iid, pif);}
|
|
|
|
#define DEFINE_QI_DELEGATE(cls, member) \
|
|
inline void cls##_QueryInterface(cls* obj, REFIID iid, void FAR* FAR* pif) \
|
|
{obj->member->QueryInterface(iid, pif);}
|
|
|
|
#define DEFINE_QI_DELEGATE_TEST(cls, member) \
|
|
inline void cls##_QueryInterface(cls* obj, REFIID iid, void FAR* FAR* pif) \
|
|
{if (obj->member) obj->member->QueryInterface(iid, pif);}
|
|
|
|
#define DEFINE_QI_MEMBER(name, member) \
|
|
void name##_QueryInterface(void far*, REFIID iid, void FAR* FAR* pif) \
|
|
{member->QueryInterface(iid, pif);}
|
|
|
|
#define DEFINE_QI_MEMBER_TEST(name, member) \
|
|
void name##_QueryInterface(void far*, REFIID iid, void FAR* FAR* pif) \
|
|
{if (member) member->QueryInterface(iid, pif);}
|
|
|
|
#define DEFINE_COMBASE_DELEGATE(cls, ifc, member) \
|
|
struct _ICLASS cls { \
|
|
cls() : member(0) {} \
|
|
ifc* member; \
|
|
DEFINE_QI_MEMBER_TEST(cls, member) \
|
|
};
|
|
|
|
#endif // OCF_OLEUTIL_H
|
|
|
|
|