- 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>
353 lines
9.0 KiB
C++
353 lines
9.0 KiB
C++
//
|
|
//----------------------------------------------------------------------------
|
|
// ObjectComponents
|
|
// (C) Copyright 1994 by Borland International, All Rights Reserved
|
|
//
|
|
// OLE Utility class implementations
|
|
//----------------------------------------------------------------------------
|
|
#include <ocf/ocfpch.h>
|
|
#include <ocf/ocdefs.h>
|
|
#include <osl/ustring.h>
|
|
|
|
DIAG_DEFINE_GROUP(OcRefCount, true, 1);
|
|
|
|
#if defined(BI_PLAT_WIN16)
|
|
const char OleErrorStringsDLL[] = "OLE_ERR.DLL";
|
|
#else
|
|
const char OleErrorStringsDLL[] = "OLE_ERRF.DLL";
|
|
#endif
|
|
|
|
|
|
TXOle::~TXOle()
|
|
{
|
|
}
|
|
|
|
TXOle* TXOle::Clone()
|
|
{
|
|
return new TXOle(*this);
|
|
}
|
|
|
|
void TXOle::Throw()
|
|
{
|
|
THROW( *this );
|
|
}
|
|
|
|
void TXOle::Check(HRESULT hr, const char far* msg)
|
|
{
|
|
if (FAILED(hr))
|
|
Throw(hr, msg);
|
|
}
|
|
|
|
void TXOle::Check(HRESULT hr)
|
|
{
|
|
Check(hr, 0);
|
|
}
|
|
|
|
void TXOle::Throw(HRESULT hr, const char far* msg)
|
|
{
|
|
if (!InstanceCount) {
|
|
char buf[128+1];
|
|
wsprintf(buf, "%s failed, ", msg ? msg : "OLE call");
|
|
|
|
int len = strlen(buf);
|
|
OleErrorFromCode(hr, buf + len, sizeof buf - len - 2);
|
|
strcat(buf, ".");
|
|
|
|
WARN(hr != HR_NOERROR, buf);
|
|
throw TXOle(buf, hr);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If OLE-Error-String DLL exists, & msg string is there, then use
|
|
// it. Otherwise just use the number.
|
|
//
|
|
void TXOle::OleErrorFromCode(HRESULT stat, char far* buffer, int size)
|
|
{
|
|
const char HResultToStringIDFunc[] = "StringIDFromHResult";
|
|
typedef int _export CALLBACK (*TStringIDFromHResult)(HRESULT hr);
|
|
|
|
int len = 0;
|
|
OFSTRUCT ofs;
|
|
if (OpenFile(OleErrorStringsDLL, &ofs, OF_EXIST) != HFILE_ERROR) {
|
|
HINSTANCE hInst = LoadLibrary(OleErrorStringsDLL);
|
|
if (hInst > (HINSTANCE)HINSTANCE_ERROR) {
|
|
TStringIDFromHResult func =
|
|
(TStringIDFromHResult)GetProcAddress(hInst, HResultToStringIDFunc);
|
|
if (func) {
|
|
int id = func(stat);
|
|
if (id)
|
|
len = ::LoadString(hInst, id, buffer, size);
|
|
}
|
|
FreeLibrary(hInst);
|
|
}
|
|
}
|
|
if (!len) {
|
|
char numBuf[25];
|
|
wsprintf(numBuf, "ErrorCode: %8lX", stat);
|
|
strncat(buffer, numBuf, size - strlen(buffer) - 1);
|
|
}
|
|
buffer[size-1] = 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
void far*
|
|
TOleAllocator::Alloc(unsigned long size)
|
|
{
|
|
void far* blk = Mem->Alloc(size);
|
|
OLECALL(blk ? 0 : HR_OUTOFMEMORY, "IMalloc::Alloc");
|
|
return blk;
|
|
}
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// TClassId - GUID/IID/CLSID management implementation
|
|
//____________________________________________________________________________
|
|
|
|
TClassId::TClassId(const char far* idtxt) : Text(0)
|
|
{
|
|
PRECONDITION(idtxt);
|
|
|
|
OLECALL(::CLSIDFromString(OleStr((char far*)idtxt), &Guid), "Invalid GUID string");
|
|
}
|
|
|
|
TClassId::TClassId(const GUID far& guid, int offset) : Text(0), Guid(guid)
|
|
{
|
|
Guid.Data1 += (long)offset;
|
|
}
|
|
|
|
TClassId::TClassId(TGenerate) : Text(0)
|
|
{
|
|
OLECALL(::CoCreateGuid(&Guid), "CoCreateGuid");
|
|
}
|
|
|
|
TClassId::~TClassId()
|
|
{
|
|
delete const_cast<char*>(Text);
|
|
}
|
|
|
|
TClassId::operator const char*()
|
|
{
|
|
if (!Text) {
|
|
Text = new char[38+1];
|
|
wsprintf(const_cast<char*>(Text),
|
|
"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
|
|
Guid.Data1, Guid.Data2, Guid.Data3,
|
|
Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3],
|
|
Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]);
|
|
}
|
|
return Text;
|
|
}
|
|
|
|
TBaseClassId::TBaseClassId(const GUID far& guid, int maxAlloc)
|
|
: TClassId(guid), MaxAlloc(maxAlloc), Offset(0) {}
|
|
|
|
TBaseClassId::TBaseClassId(const char far* idtxt, int maxAlloc)
|
|
: TClassId(idtxt), MaxAlloc(maxAlloc), Offset(0) {}
|
|
|
|
TBaseClassId::TBaseClassId(TGenerate e, int maxAlloc)
|
|
: TClassId(e), MaxAlloc(maxAlloc), Offset(0) {}
|
|
|
|
TBaseClassId::TBaseClassId(TRegList& regInfo, int maxAlloc)
|
|
: TClassId(), MaxAlloc(maxAlloc), Offset(0)
|
|
{
|
|
const char* str = regInfo["clsid"];
|
|
// must check for valid clasid, else generate??
|
|
if (!str)
|
|
OLECALL(HR_CLASS_CLASSNOTAVAILABLE, "Missing REGDATA clsid");
|
|
OLECALL(::CLSIDFromString(OleStr((char far*)str), &Guid), "Invalid GUID string");
|
|
}
|
|
|
|
TClassId TBaseClassId::operator [](int offset)
|
|
{
|
|
if(offset > Offset)
|
|
OLECALL(HR_CLASS_CLASSNOTAVAILABLE, "Unassigned GUID");
|
|
return TClassId(Guid, offset);
|
|
}
|
|
|
|
int TBaseClassId::AllocId()
|
|
{
|
|
++Offset;
|
|
if(Offset >= MaxAlloc)
|
|
OLECALL(HR_CLASS_CLASSNOTAVAILABLE, "GUID allocation exhausted");
|
|
return Offset;
|
|
}
|
|
|
|
int TBaseClassId::GetOffset(const GUID far& guid)
|
|
{
|
|
unsigned long offset = guid.Data1 - Guid.Data1;
|
|
if ( offset >= (unsigned long)Offset &&
|
|
((long far*)&guid)[1] == ((long*)&Guid)[1] &&
|
|
((long far*)&guid)[2] == ((long*)&Guid)[2] &&
|
|
((long far*)&guid)[3] == ((long*)&Guid)[3] )
|
|
return int(offset);
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// GUID compare routines use by implementations of IUnknown::QueryInterface
|
|
// the low-order long word is verifed before calling these routines
|
|
// success is indicated by virtue of assigment of the returned interface
|
|
//____________________________________________________________________________
|
|
|
|
void CmpGuid12(IUnknown* obj, REFIID req, REFIID ref, void far*far* pif)
|
|
{
|
|
if ( ((long far*)&req)[1] == ((long far*)&ref)[1] &&
|
|
((long far*)&req)[2] == ((long far*)&ref)[2] &&
|
|
((long far*)&req)[3] == ((long far*)&ref)[3] ) {
|
|
*pif = obj;
|
|
obj->AddRef();
|
|
}
|
|
}
|
|
|
|
void CmpGuidOle(IUnknown* obj, REFIID req, void far*far* pif)
|
|
{
|
|
if ( ((long far*)&req)[1] == 0x00000000L &&
|
|
((long far*)&req)[2] == 0x000000C0L &&
|
|
((long far*)&req)[3] == 0x46000000L ) {
|
|
*pif = obj;
|
|
obj->AddRef();
|
|
}
|
|
}
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// TUnknown - standard implementation of IUnknown
|
|
//____________________________________________________________________________
|
|
|
|
//
|
|
// Handy container to help watch COM object lifetime when debugging
|
|
//
|
|
#if (__DEBUG >= 2)
|
|
# include <classlib/bags.h>
|
|
typedef TBagAsVector<TUnknown*> TUnknownBag;
|
|
TUnknownBag* UnknownBag;
|
|
#endif
|
|
|
|
TUnknown::TUnknown() : Outer(&I)
|
|
{
|
|
#if (__DEBUG >= 2)
|
|
if (!UnknownBag)
|
|
UnknownBag = new TUnknownBag(100);
|
|
UnknownBag->Add(this);
|
|
#endif
|
|
}
|
|
|
|
IUnknown& TUnknown::Aggregate(TUnknown& inner)
|
|
{
|
|
if (I.Inner)
|
|
return I.Inner->Aggregate(inner);
|
|
((IUnknown&)inner).AddRef();
|
|
I.Inner = &inner;
|
|
return *Outer;
|
|
}
|
|
|
|
TUnknown::~TUnknown()
|
|
{
|
|
#if (__DEBUG >= 2)
|
|
UnknownBag->Detach(this);
|
|
#endif
|
|
TRACEX(OcRefCount, 1,
|
|
"~TUnknown() @" << (void*)this << ", RefCnt:" << I.RefCnt);
|
|
WARNX(OcRefCount, I.RefCnt != 0, 0,
|
|
"~TUnknown() @ " << (void*)this << ", RefCnt:" << I.RefCnt);
|
|
|
|
// deleted by TUnknownI member
|
|
}
|
|
|
|
//
|
|
// QueryObject used when TUnknown is in constructor/destructor
|
|
//
|
|
HRESULT
|
|
TUnknown::QueryObject(const GUID far& /*iid*/, void far* far* /*pif*/)
|
|
{
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
HRESULT _IFUNC
|
|
TUnknown::TUnknownI::QueryInterface(const GUID far& iid, void far* far* pif)
|
|
{
|
|
*pif = 0;
|
|
if (iid.Data1 == 0) { // IID_IUnknown.Data1
|
|
CmpGuidOle(this, iid, pif);
|
|
if (*pif)
|
|
return NOERROR;
|
|
}
|
|
if (Host().QueryObject(iid, pif) == NOERROR)
|
|
return NOERROR;
|
|
if (Inner)
|
|
return Inner->ThisUnknown().QueryInterface(iid, pif);
|
|
else
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
unsigned long _IFUNC
|
|
TUnknown::TUnknownI::AddRef()
|
|
{
|
|
TRACEX(OcRefCount, 2,
|
|
"AddRef on " << (void*)&Host() << " to " << (RefCnt+1));
|
|
return ++RefCnt;
|
|
}
|
|
|
|
unsigned long _IFUNC
|
|
TUnknown::TUnknownI::Release()
|
|
{
|
|
TRACEX(OcRefCount, 2,
|
|
"Release on " << (void*)&Host() << " to " << (RefCnt-1));
|
|
if (--RefCnt != 0)
|
|
return RefCnt;
|
|
if (Inner) {
|
|
Inner->ThisUnknown().Release();
|
|
Inner = 0;
|
|
}
|
|
delete &Host();
|
|
return 0;
|
|
}
|
|
|
|
unsigned long
|
|
TUnknown::GetRefCount()
|
|
{
|
|
if (Outer == &I)
|
|
return I.RefCnt;
|
|
Outer->AddRef();
|
|
return Outer->Release();
|
|
}
|
|
|
|
TUnknown::TUnknownI::~TUnknownI()
|
|
{
|
|
if (RefCnt) // in case destructor called before RefCnt goes to 0
|
|
::CoDisconnectObject(this,0);// OLE will try to remove external references
|
|
}
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// TLocaleString wrapper method replacements using OLE2 NLS functions for Win16
|
|
//____________________________________________________________________________
|
|
|
|
#if defined(BI_PLAT_WIN16)
|
|
|
|
TLangId
|
|
TLocaleString::GetSystemLangId()
|
|
{
|
|
return ::GetSystemDefaultLangID();
|
|
}
|
|
|
|
TLangId
|
|
TLocaleString::GetUserLangId()
|
|
{
|
|
return ::GetUserDefaultLangID();
|
|
}
|
|
|
|
int
|
|
TLocaleString::CompareLang(const char far* s1, const char far* s2, TLangId lang)
|
|
{
|
|
return ::CompareStringA(lang, NORM_IGNORECASE | NORM_IGNORENONSPACE,
|
|
s1,-1, s2,-1) - 2;
|
|
}
|
|
|
|
#endif
|
|
|