- 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>
257 lines
7.0 KiB
C++
257 lines
7.0 KiB
C++
//----------------------------------------------------------------------------
|
|
// ObjectWindows - (C) Copyright 1993 by Borland International
|
|
//
|
|
// This example shows a persistent desktop using the MDI metaphor. It is
|
|
// identical to the owlapi\mdi example, but with streaming code added to
|
|
// implement persistence for the frame, parent (client) window, and children.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#include <owl\owlpch.h>
|
|
#include <owl\applicat.h>
|
|
#include <owl\mdi.h>
|
|
#include <owl\mdichild.h>
|
|
#include <stdio.h>
|
|
#include "mdistrm.h"
|
|
|
|
const char DskFile[] = "MDISTRM.SAV";
|
|
const char AppName[] = "MDI Object Streaming Example";
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
// Here's our client, it's fully streamable.
|
|
//
|
|
class TMyMDIClient : public TMDIClient {
|
|
public:
|
|
TMyMDIClient() : TMDIClient() {ChildNum = 0;}
|
|
|
|
TMDIChild* InitChild();
|
|
BOOL CanClose(); //virtual from TWindow
|
|
|
|
private:
|
|
WORD ChildNum;
|
|
|
|
DECLARE_STREAMABLE(, TMyMDIClient, 1);
|
|
};
|
|
|
|
IMPLEMENT_CASTABLE1(TMyMDIClient, TMDIClient);
|
|
IMPLEMENT_STREAMABLE1(TMyMDIClient, TMDIClient);
|
|
|
|
//
|
|
// Our application object is also fully streamable and
|
|
// we use it to stream out its client (which contains the
|
|
// MDI child windows) to achieve a persistent desktop.
|
|
//
|
|
class TMDIApp : public TApplication {
|
|
public:
|
|
TMDIApp() : TApplication(AppName) {}
|
|
void InitMainWindow();
|
|
void InitInstance();
|
|
void CmSaveState();
|
|
void CmRestoreState();
|
|
|
|
private:
|
|
TMyMDIClient* Client;
|
|
|
|
DECLARE_RESPONSE_TABLE(TMDIApp);
|
|
DECLARE_STREAMABLE(, TMDIApp, 1);
|
|
};
|
|
|
|
DEFINE_RESPONSE_TABLE1(TMDIApp, TApplication)
|
|
EV_COMMAND(CM_SAVESTATE, CmSaveState),
|
|
EV_COMMAND(CM_RESTORESTATE, CmRestoreState),
|
|
END_RESPONSE_TABLE;
|
|
|
|
IMPLEMENT_CASTABLE1(TMDIApp, TApplication);
|
|
IMPLEMENT_STREAMABLE1(TMDIApp, TApplication);
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
TMDIChild*
|
|
TMyMDIClient::InitChild()
|
|
{
|
|
char childName[15];
|
|
|
|
// Create a unique (numbered) caption for our MDI child
|
|
sprintf(childName, "MDI Child %d", ChildNum++);
|
|
|
|
// and then create that child.
|
|
return new TMDIChild(*this, childName);
|
|
}
|
|
|
|
BOOL
|
|
TMyMDIClient::CanClose()
|
|
{
|
|
// Save our persistent desktop, before closing down the client.
|
|
// We have to (safely and dynamically) cast to our application
|
|
// object type so that we can call our save state routine.
|
|
//
|
|
TMDIApp *app = TYPESAFE_DOWNCAST(GetApplication(),TMDIApp);
|
|
if (app)
|
|
app->CmSaveState();
|
|
|
|
return TMDIClient::CanClose();
|
|
}
|
|
|
|
//
|
|
// Writes the TMyMDIClient instance to the passed opstream.
|
|
//
|
|
void
|
|
TMyMDIClient::Streamer::Write(opstream& os) const
|
|
{
|
|
WriteBaseObject((TMDIClient*)GetObject(), os);
|
|
|
|
// Write out the member data for our MDI Client.
|
|
os << GetObject()->ChildNum;
|
|
}
|
|
|
|
//
|
|
// Reads an instance of TMyMDIClient from the passed ipstream.
|
|
//
|
|
void *
|
|
TMyMDIClient::Streamer::Read(ipstream& is, uint32 /*version*/) const
|
|
{
|
|
ReadBaseObject((TMDIClient*)GetObject(), is);
|
|
|
|
// Read in the member data for our MDI Client.
|
|
is >> GetObject()->ChildNum;
|
|
|
|
return GetObject();
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
// Construct the TMDIApp's MainWindow (frame) object and save
|
|
// a pointer to its client window in the Client data member.
|
|
// Restore the desktop if we've got one already streamed.
|
|
//
|
|
void
|
|
TMDIApp::InitMainWindow()
|
|
{
|
|
// Create MDI frame window, load its menu, and create its client.
|
|
MainWindow = new TMDIFrame(GetName(), "MDIMenu", *(Client=new TMyMDIClient));
|
|
}
|
|
|
|
void
|
|
TMDIApp::InitInstance()
|
|
{
|
|
TApplication::InitInstance();
|
|
|
|
// Restore our persistent desktop, if there's a stream that already exists.
|
|
ifpstream is(DskFile);
|
|
if (!is.bad())
|
|
{
|
|
is.close();
|
|
CmRestoreState();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Save the the position and contents of the windows to the "desktop" file.
|
|
//
|
|
void
|
|
TMDIApp::CmSaveState()
|
|
{
|
|
ofpstream os(DskFile);
|
|
|
|
// Stream out 'this' object (our MDI application and children).
|
|
os << *this;
|
|
|
|
os.close();
|
|
|
|
if (os.bad()) {
|
|
unlink(DskFile);
|
|
MainWindow->MessageBox("Unable to write desktop file.", "Disk error",
|
|
MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Read windows' positions and contents from the "desktop" file.
|
|
//
|
|
void
|
|
TMDIApp::CmRestoreState()
|
|
{
|
|
char* errorMsg = 0;
|
|
|
|
ifpstream is(DskFile);
|
|
if (is.bad())
|
|
errorMsg = "Unable to open desktop file.";
|
|
|
|
else {
|
|
// Close any MDI children we may have.
|
|
Client->CloseChildren();
|
|
try {
|
|
// Stream into 'this' object our (new) MDI application and children.
|
|
is >> *this;
|
|
if (is.bad())
|
|
errorMsg = "Error reading desktop file.";
|
|
}
|
|
catch (xalloc) {
|
|
if (Client->HWindow)
|
|
Client->CloseChildren();
|
|
errorMsg = "Not enough memory to open file.";
|
|
}
|
|
is.close();
|
|
}
|
|
if (errorMsg)
|
|
MainWindow->MessageBox(errorMsg, "Error", MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
|
|
void
|
|
TMDIApp::Streamer::Write(opstream& os) const
|
|
{
|
|
// Stream out our app's mainwindow size/coordinates and our client
|
|
// window (the client will stream any child windows it may contain).
|
|
WriteBaseObject((TApplication*)GetObject(), os);
|
|
os << GetObject()->MainWindow->Attr.X;
|
|
os << GetObject()->MainWindow->Attr.Y;
|
|
os << GetObject()->MainWindow->Attr.W;
|
|
os << GetObject()->MainWindow->Attr.H;
|
|
|
|
os << *( GetObject()->Client );
|
|
os << GetObject()->Client->GetActiveMDIChild();
|
|
}
|
|
|
|
void *
|
|
TMDIApp::Streamer::Read(ipstream& is, uint32 /*version*/ ) const
|
|
{
|
|
// Stream in our app's mainwindow frame coordinates, updating its frame
|
|
// size, and stream in its client window.
|
|
ReadBaseObject((TApplication*)GetObject(), is);
|
|
is >> GetObject()->MainWindow->Attr.X;
|
|
is >> GetObject()->MainWindow->Attr.Y;
|
|
is >> GetObject()->MainWindow->Attr.W;
|
|
is >> GetObject()->MainWindow->Attr.H;
|
|
|
|
is >> *( GetObject()->Client );
|
|
TMDIChild* active;
|
|
is >> active;
|
|
|
|
// If our mainwindow already exists (i.e., we're restoring from the menu)
|
|
// then make sure it's redrawn correctly, with the 'new' extent attributes
|
|
// (what they were when they were last streamed to file).
|
|
if (GetObject()->MainWindow->HWindow)
|
|
GetObject()->MainWindow->MoveWindow(GetObject()->MainWindow->Attr.X,
|
|
GetObject()->MainWindow->Attr.Y,
|
|
GetObject()->MainWindow->Attr.W,
|
|
GetObject()->MainWindow->Attr.H,
|
|
TRUE);
|
|
|
|
// Finally, create the interface objects for our children,
|
|
// restoring the active window.
|
|
GetObject()->Client->CreateChildren();
|
|
if (active)
|
|
GetObject()->Client->HandleMessage(WM_MDIACTIVATE,(UINT)active->HWindow);
|
|
return GetObject();
|
|
}
|
|
|
|
int
|
|
OwlMain(int /*argc*/, char* /*argv*/ [])
|
|
{
|
|
return TMDIApp().Run();
|
|
}
|