- 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>
428 lines
10 KiB
C++
428 lines
10 KiB
C++
//----------------------------------------------------------------------------
|
|
// ObjectWindows
|
|
// (C) Copyright 1991, 1994 by Borland International, All Rights Reserved
|
|
//
|
|
// Implementation of class TAppDictionary, a dictionary of
|
|
// associations between pids (Process IDs) and TApplication pointers.
|
|
// Used to support GetApplicationObject().
|
|
//----------------------------------------------------------------------------
|
|
#include <owl/owlpch.h>
|
|
#include <owl/appdict.h>
|
|
#include <owl/applicat.h>
|
|
#if defined(BI_APP_DLL)
|
|
# include <dos.h>
|
|
# include <string.h>
|
|
#endif
|
|
|
|
//#define LOCALALLOC_TABLE // define to use local alloc for table
|
|
|
|
//
|
|
// Global dictionary used by OWL for EXE Application lookup
|
|
//
|
|
TAppDictionary _OWLDATA OwlAppDictionary;
|
|
|
|
//
|
|
// Dictionary implementation used to associate Pids (hTasks) with running Owl
|
|
// apps when Owl is in a DLL or used by a DLL. 32bit only needs this when
|
|
// running win32s (no per-instance data) since per-instance data makes it
|
|
// unnecesasry
|
|
//
|
|
#if defined(BI_APP_DLL) || defined(BI_PLAT_WIN32)
|
|
|
|
//
|
|
// Abstract Base for dictionary implementation
|
|
//
|
|
class TAppDictImp {
|
|
public:
|
|
virtual ~TAppDictImp() {}
|
|
|
|
virtual void Add(unsigned pid, TApplication* app) = 0;
|
|
virtual void Remove(unsigned pid) = 0;
|
|
virtual TAppDictionary::TEntry* Lookup(unsigned pid) = 0;
|
|
virtual TAppDictionary::TEntry* Lookup(TApplication* app) = 0;
|
|
virtual void Iterate(TAppDictionary::TEntryIterator) = 0;
|
|
virtual int GetCount() const = 0;
|
|
};
|
|
|
|
//
|
|
// Pid based Dictionary implementation for Win16, or Win32 w/o perinstance data
|
|
//
|
|
class TAppDictPidImp : public TAppDictImp {
|
|
public:
|
|
TAppDictPidImp();
|
|
~TAppDictPidImp();
|
|
|
|
void Add(unsigned pid, TApplication* app);
|
|
void Remove(unsigned pid);
|
|
TAppDictionary::TEntry* Lookup(unsigned pid);
|
|
TAppDictionary::TEntry* Lookup(TApplication* app);
|
|
void Iterate(TAppDictionary::TEntryIterator iter);
|
|
int GetCount() const;
|
|
|
|
private:
|
|
enum {DefDictionarySize = 10};
|
|
enum {DefDictionaryIncrement = 10};
|
|
|
|
static TAppDictionary::TEntry* AllocTable(int count);
|
|
static void FreeTable(TAppDictionary::TEntry* table);
|
|
TAppDictionary::TEntry* GrowTable();
|
|
|
|
int NumEntries;
|
|
TAppDictionary::TEntry* Table;
|
|
};
|
|
|
|
#if defined(BI_PLAT_WIN32)
|
|
//
|
|
// Local flag used for Win32 to skip dictionary when per-instance data is
|
|
// available. Assume per-instance data is only unsupported in Win32s
|
|
//
|
|
static int PerInstanceData =
|
|
!( (::GetVersion()&0x80000000) && (::GetVersion()&0xFF) < 4);
|
|
|
|
//
|
|
// Fast, small, per-instance data based Dictionary implementation (32bit only)
|
|
//
|
|
class TAppDictInstImp : public TAppDictImp {
|
|
public:
|
|
TAppDictInstImp() {Entry.App = 0;}
|
|
|
|
void Add(unsigned pid, TApplication* app) {Entry.App = app;}
|
|
void Remove(unsigned) {Entry.App = 0;}
|
|
TAppDictionary::TEntry* Lookup(unsigned) {return &Entry;}
|
|
TAppDictionary::TEntry* Lookup(TApplication* app) {return &Entry;}
|
|
void Iterate(TAppDictionary::TEntryIterator iter)
|
|
{(*iter)(Entry);}
|
|
int GetCount() const {return Entry.App ? 1 : 0;}
|
|
|
|
private:
|
|
TAppDictionary::TEntry Entry;
|
|
};
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------
|
|
// TAppDictionary implementation for DLLs only. EXE version is all inline.
|
|
// Flat model must implement here, not inline, because same lib is used by DLLs
|
|
//
|
|
|
|
//
|
|
// Application dictionary constructor
|
|
//
|
|
TAppDictionary::TAppDictionary()
|
|
{
|
|
#if defined(BI_PLAT_WIN32)
|
|
if (PerInstanceData) // could also use this case if linked to exe
|
|
Imp = new TAppDictInstImp();
|
|
else
|
|
Imp = new TAppDictPidImp();
|
|
#else
|
|
Imp = new TAppDictPidImp();
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
TAppDictionary::~TAppDictionary()
|
|
{
|
|
DeleteCondemned();
|
|
delete Imp;
|
|
}
|
|
|
|
//
|
|
// Lookup and return the app assiciated with a given pid. May return 0.
|
|
//
|
|
TApplication*
|
|
TAppDictionary::GetApplication(unsigned pid)
|
|
{
|
|
if (!pid)
|
|
pid = ::GetCurrentProcessId();
|
|
TAppDictionary::TEntry* entry = Imp->Lookup(pid);
|
|
return entry ? entry->App : 0;
|
|
}
|
|
|
|
//
|
|
// Add an app to this dictionary
|
|
//
|
|
void
|
|
TAppDictionary::Add(TApplication* app, unsigned pid)
|
|
{
|
|
if (!pid)
|
|
pid = ::GetCurrentProcessId();
|
|
Imp->Add(pid, app);
|
|
}
|
|
|
|
//
|
|
// Remove a given app from this dictionary
|
|
//
|
|
void
|
|
TAppDictionary::Remove(TApplication* app)
|
|
{
|
|
TAppDictionary::TEntry* entry = Imp->Lookup(app);
|
|
if (entry) {
|
|
entry->App = 0;
|
|
entry->Pid = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Remove the app associated with a given pid from this dictionary
|
|
//
|
|
void
|
|
TAppDictionary::Remove(unsigned pid)
|
|
{
|
|
TAppDictionary::TEntry* entry = Imp->Lookup(pid);
|
|
if (entry) {
|
|
entry->App = 0;
|
|
entry->Pid = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Mark an app in this dictionary as being condemned by zeroing its pid.
|
|
// Can then be deleted later.
|
|
//
|
|
void
|
|
TAppDictionary::Condemn(TApplication* app)
|
|
{
|
|
TAppDictionary::TEntry* entry = Imp->Lookup(app);
|
|
if (entry)
|
|
entry->Pid = 0;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
static void sDeleteCondemnedIter(TAppDictionary::TEntry& entry)
|
|
{
|
|
if (!entry.Pid) {
|
|
delete entry.App;
|
|
entry.App = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void
|
|
TAppDictionary::Iterate(TAppDictionary::TEntryIterator iter)
|
|
{
|
|
Imp->Iterate(iter);
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
bool
|
|
TAppDictionary::DeleteCondemned()
|
|
{
|
|
Imp->Iterate(sDeleteCondemnedIter);
|
|
return Imp->GetCount() == 0;
|
|
}
|
|
|
|
//
|
|
// Exported entry for Debugger use
|
|
//
|
|
extern "C" TApplication* PASCAL _OWLFUNC
|
|
GetTaskApplicationObject(unsigned pid)
|
|
{
|
|
return ::OwlAppDictionary.GetApplication(pid);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// TAppDictPidImp for DLL when there are real guts for pid lookup
|
|
//
|
|
|
|
TAppDictPidImp::TAppDictPidImp()
|
|
{
|
|
Table = AllocTable(DefDictionarySize);
|
|
NumEntries = DefDictionarySize;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
TAppDictPidImp::~TAppDictPidImp()
|
|
{
|
|
FreeTable(Table);
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void
|
|
TAppDictPidImp::Add(unsigned pid, TApplication* app)
|
|
{
|
|
TAppDictionary::TEntry* freeEntry = 0; // no free entry yet
|
|
|
|
// First see if there is already a table; if so, replace the entry
|
|
//
|
|
for (TAppDictionary::TEntry* entry = Table; entry < &Table[NumEntries]; entry++) {
|
|
if (entry->Pid == pid) {
|
|
// Old app gets stomped, user must manage its lifetime
|
|
entry->App = app; // already in table, update pointers
|
|
return;
|
|
}
|
|
else if (!freeEntry && !entry->Pid) {
|
|
freeEntry = entry; // remember this first free entry for use later
|
|
}
|
|
}
|
|
|
|
// Not in table. see if we encountered a free entry in the table
|
|
// if so, use it; otherwise grow the table & put entry in first new slot
|
|
//
|
|
entry = freeEntry ? freeEntry : GrowTable();
|
|
entry->Pid = pid;
|
|
entry->App = app;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void
|
|
TAppDictPidImp::Remove(unsigned pid)
|
|
{
|
|
TAppDictionary::TEntry* entry = Lookup(pid);
|
|
if (entry) {
|
|
entry->App = 0;
|
|
entry->Pid = 0;
|
|
}
|
|
}
|
|
//
|
|
// Lookup and return the entry associated with a given pid. May return 0.
|
|
//
|
|
TAppDictionary::TEntry*
|
|
TAppDictPidImp::Lookup(unsigned pid)
|
|
{
|
|
for (TAppDictionary::TEntry* entry = Table; entry < Table+NumEntries; entry++)
|
|
if (entry->Pid == pid)
|
|
return entry;
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Lookup and return the entry associated with a given app. May return 0.
|
|
//
|
|
TAppDictionary::TEntry*
|
|
TAppDictPidImp::Lookup(TApplication* app)
|
|
{
|
|
for (TAppDictionary::TEntry* entry = Table; entry < Table+NumEntries; entry++)
|
|
if (entry->App == app)
|
|
return entry;
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void
|
|
TAppDictPidImp::Iterate(TAppDictionary::TEntryIterator iter)
|
|
{
|
|
for (TAppDictionary::TEntry* entry = Table; entry < Table+NumEntries; entry++)
|
|
(*iter)(*entry);
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
int
|
|
TAppDictPidImp::GetCount() const
|
|
{
|
|
int i = 0;
|
|
for (TAppDictionary::TEntry* entry = Table; entry < Table+NumEntries; entry++)
|
|
if (entry->App)
|
|
i++;
|
|
return i;
|
|
}
|
|
|
|
//
|
|
// Allocate the table from the local heap so that this DLL always owns it.
|
|
//
|
|
TAppDictionary::TEntry*
|
|
TAppDictPidImp::AllocTable(int count)
|
|
{
|
|
TAppDictionary::TEntry* entries;
|
|
#if defined(LOCALALLOC_TABLE)
|
|
entries = (TAppDictionary::TEntry*)::LocalLock(::LocalAlloc(LMEM_ZEROINIT,
|
|
count * sizeof(TAppDictionary::TEntry)));
|
|
if (!entries)
|
|
THROW( xalloc(__FILE__ __LINE__, count * sizeof(TAppDictionary::TEntry)) );
|
|
#else
|
|
entries = new TAppDictionary::TEntry[count];
|
|
memset(entries, 0, count * sizeof(TAppDictionary::TEntry));
|
|
#endif
|
|
return entries;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void
|
|
TAppDictPidImp::FreeTable(TAppDictionary::TEntry* table)
|
|
{
|
|
#if defined(LOCALALLOC_TABLE)
|
|
if (!table)
|
|
return;
|
|
#if defined(BI_PLAT_WIN32)
|
|
HLOCAL hMem = ::LocalHandle(table);
|
|
#else
|
|
HLOCAL hMem = ::LocalHandle((void NEAR*)FP_OFF(table)); // strip off ds:
|
|
#endif
|
|
if (::LocalUnlock(hMem))
|
|
::LocalFree(hMem);
|
|
#else
|
|
delete[] table;
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
TAppDictionary::TEntry*
|
|
TAppDictPidImp::GrowTable()
|
|
{
|
|
// Save current table & entry count, & create new ones
|
|
//
|
|
int oldNumEntries = NumEntries;
|
|
TAppDictionary::TEntry* oldTable = Table;
|
|
|
|
NumEntries += DefDictionaryIncrement;
|
|
Table = AllocTable(NumEntries);
|
|
|
|
// copy old table to new one
|
|
//
|
|
memcpy(Table, oldTable, oldNumEntries * sizeof(TAppDictionary::TEntry));
|
|
|
|
// Free old table
|
|
//
|
|
FreeTable(oldTable);
|
|
|
|
// return pointer to first entry in new block
|
|
//
|
|
return Table + oldNumEntries;
|
|
}
|
|
|
|
#endif // defined(BI_APP_DLL)
|
|
|
|
//
|
|
// Global function that calls GetApplication() on owl's app-dictionary.
|
|
// Used by EXEs, or DLLs statically linking Owl. Never returns 0, will make
|
|
// an alias app if needed. Primarily for compatibility
|
|
//
|
|
TApplication* _OWLFUNC GetApplicationObject(unsigned pid)
|
|
{
|
|
TApplication* app = ::OwlAppDictionary.GetApplication(pid);
|
|
if (app)
|
|
return app;
|
|
|
|
// Make alias app (will add itself to dictionary) because Owl always needs an
|
|
// app around. If the app is non-Owl, no TApplication will have been
|
|
// constructed.
|
|
// Override default constructor argument to prevent overwrite of ::Module,
|
|
// and pass the default dictionary.
|
|
//
|
|
TModule* tempModule;
|
|
return new TApplication("ALIAS", tempModule, &OwlAppDictionary);
|
|
}
|