- 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>
406 lines
9.6 KiB
C++
406 lines
9.6 KiB
C++
//
|
|
//**************************************************************************
|
|
//
|
|
// BOleCont.cpp -- Implements the server helper for documents by masquerading
|
|
// as the container object. Provides plumbing for server
|
|
// linking to documents and items
|
|
//
|
|
// Copyright (c) 1993,94 by Borland International, Inc. All rights reserved
|
|
//
|
|
//**************************************************************************
|
|
|
|
#include "BOleCont.h"
|
|
#include "BOleFact.h"
|
|
#include "BOleCMan.h"
|
|
#include "BOlePart.h" // for link or embed to embedding
|
|
|
|
HRESULT _IFUNC BOleContainer::QueryInterfaceMain(REFIID iid, LPVOID FAR *ppv)
|
|
{
|
|
HRESULT hr = ResultFromScode(E_NOINTERFACE);
|
|
*ppv = NULL;
|
|
|
|
// interfaces
|
|
|
|
SUCCEEDED(hr = IBRootLinkable_QueryInterface(this, iid, ppv))
|
|
|| SUCCEEDED(hr = IPersistFile_QueryInterface(this, iid, ppv))
|
|
|| SUCCEEDED(hr = IOleItemContainer_QueryInterface(this, iid, ppv))
|
|
//
|
|
// base classes
|
|
|
|
|| SUCCEEDED(hr = BOleComponent::QueryInterfaceMain(iid, ppv))
|
|
|
|
// helpers
|
|
;
|
|
return hr;
|
|
};
|
|
|
|
BOleContainer::BOleContainer (BOleClassManager *pF, IBUnknownMain * pObj) :
|
|
BOleComponent(pF, pObj)
|
|
{
|
|
pDoc = NULL;
|
|
regId = 0L;
|
|
pMoniker = NULL;
|
|
pClassFact = NULLP;
|
|
}
|
|
|
|
BOleContainer::~BOleContainer ()
|
|
{
|
|
if (pClassFact) {
|
|
pClassFact->Release ();
|
|
pClassFact = NULL;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/
|
|
// IOleItemContainer
|
|
/**************************************************************************/
|
|
|
|
HRESULT _IFUNC BOleContainer::GetClassID (LPCLSID lpClassID)
|
|
{
|
|
HRESULT hrErr = ResultFromScode (E_FAIL);
|
|
// outer could have called IRootLinkable::Init.
|
|
if (lpClassID && pClassFact) {
|
|
hrErr = pClassFact->GetClassID(lpClassID);
|
|
}
|
|
else {
|
|
// this is sometimes called for documents not attached to servers!
|
|
*lpClassID = CLSID_NULL;
|
|
}
|
|
return hrErr;
|
|
}
|
|
|
|
HRESULT _IFUNC BOleContainer::IsDirty ()
|
|
{
|
|
HRESULT hrErr = ResultFromScode (S_OK);
|
|
|
|
//
|
|
|
|
return hrErr;
|
|
}
|
|
|
|
#define OLE_MAXNAMESIZE (256)
|
|
|
|
HRESULT _IFUNC BOleContainer::ParseDisplayName (IBindCtx *pbc, LPOLESTR pszDisplayName,
|
|
ULONG FAR* pchEaten, IMoniker* FAR* ppmk)
|
|
{
|
|
*ppmk = NULL;
|
|
|
|
OLECHAR szItemName[OLE_MAXNAMESIZE];
|
|
OLECHAR *pszDest = szItemName;
|
|
LPCTSTR pszSrc = pszDisplayName;
|
|
|
|
// skip leading delimiters
|
|
int cEaten = 0;
|
|
while (*pszSrc != '\0' && (*pszSrc == '\\' || *pszSrc == '/' ||
|
|
*pszSrc == '!' || *pszSrc == '['))
|
|
{
|
|
++pszSrc;
|
|
++cEaten;
|
|
}
|
|
|
|
// parse next token into szItemName
|
|
while (*pszSrc != '\0' && *pszSrc != '\\' && *pszSrc != '/' &&
|
|
*pszSrc != '!' && *pszSrc != '[' && cEaten < OLE_MAXNAMESIZE-1)
|
|
{
|
|
*pszDest++ = *pszSrc++;
|
|
++cEaten;
|
|
}
|
|
*pchEaten = cEaten;
|
|
*pszDest = 0;
|
|
|
|
// attempt to get the object
|
|
LPUNKNOWN pUnknown;
|
|
HRESULT hr = GetObject(szItemName, BINDSPEED_INDEFINITE, pbc,
|
|
IID_IUnknown, &(LPVOID)pUnknown);
|
|
if (SUCCEEDED(hr)) {
|
|
pUnknown->Release();
|
|
// item name found -- create item moniker for it
|
|
return ::CreateItemMoniker(OLESTDDELIM, szItemName, ppmk);
|
|
}
|
|
else {
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT _IFUNC BOleContainer::EnumObjects (DWORD, IEnumUnknown* FAR* ppenumUnknown)
|
|
{
|
|
HRESULT hrErr = ResultFromScode(E_NOTIMPL);
|
|
*ppenumUnknown = NULLP;
|
|
return hrErr;
|
|
}
|
|
|
|
HRESULT _IFUNC BOleContainer::LockContainer (BOOL fLock)
|
|
{
|
|
// Keep app from closing
|
|
//
|
|
pFactory->ServerCount(fLock ? +1 : -1);
|
|
// Lock external, but pass FALSE as last arg, so in-proc "self" linking
|
|
// work (otherwise, Close gets called).
|
|
//
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
if (fLock)
|
|
AddRef();
|
|
else
|
|
Release();
|
|
|
|
return NOERROR;
|
|
|
|
//
|
|
}
|
|
|
|
HRESULT _IFUNC BOleContainer::GetObject (LPOLESTR lpszItem,
|
|
DWORD dwSpeedNeeded, IBindCtx* pbc, REFIID riid, LPVOID FAR* ppvObject)
|
|
{
|
|
HRESULT hrErr = ResultFromScode(MK_E_NOOBJECT);
|
|
*ppvObject = NULL;
|
|
PIBPart pPart;
|
|
if (SUCCEEDED(pDoc->GetPart(& pPart, lpszItem))) {
|
|
// bind speed always INDEFINITE? p.803
|
|
IUnknown *pUnk = pPart;
|
|
BOleSite *pBOleSite;
|
|
BOlePart *pBOlePart;
|
|
if (SUCCEEDED(pUnk->QueryInterface(IID_BOlePart, &(LPVOID)pBOlePart))) {
|
|
// Link to embedding case give the real IOleObject
|
|
//
|
|
if (pBOlePart->pOleObject) {
|
|
pUnk = pBOlePart->pOleObject;
|
|
}
|
|
// Links to items need to maintain locks on their document
|
|
// or the ProxyManager gets hosed.
|
|
// When the BOlePart goes away it unlocks this.
|
|
//
|
|
if (!pBOlePart->pDocument) // only ONCE
|
|
pBOlePart->pDocument = AsPIUnknown(pObjOuter);
|
|
CoLockObjectExternal(AsPIUnknown(pObjOuter), TRUE, TRUE);
|
|
pBOlePart->Release();
|
|
}
|
|
else if (SUCCEEDED(pUnk->QueryInterface(IID_BOleSite, &(LPVOID)pBOleSite))) {
|
|
// Links to items need maintain locks on their documents
|
|
// or the ProxyManager gets hosed.
|
|
// When the BOleSite goes away it unlocks this.
|
|
//
|
|
if (!pBOleSite->pDocument) // only ONCE
|
|
pBOleSite->pDocument = AsPIUnknown(pObjOuter);
|
|
pBOleSite->pDocument = AsPIUnknown(pObjOuter);
|
|
CoLockObjectExternal(AsPIUnknown(pObjOuter), TRUE, TRUE);
|
|
pBOleSite->Release();
|
|
}
|
|
if (SUCCEEDED(hrErr=OleRun(pUnk))) {
|
|
hrErr = pUnk->QueryInterface( riid, ppvObject);
|
|
}
|
|
pPart->Release();
|
|
pPart = NULL;
|
|
}
|
|
return hrErr;
|
|
}
|
|
|
|
HRESULT _IFUNC BOleContainer::GetObjectStorage (LPOLESTR lpszItem, IBindCtx* pbc, REFIID riid, LPVOID FAR* ppvStorage)
|
|
{
|
|
*ppvStorage = NULL;
|
|
|
|
if (riid != IID_IStorage)
|
|
return ResultFromScode(E_UNEXPECTED);
|
|
|
|
// could get part and ask for BOlePart or BOleSite
|
|
// and get the pStorage out of there
|
|
// noone calls this
|
|
|
|
return ResultFromScode(MK_E_NOSTORAGE);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleContainer::IsRunning (LPOLESTR lpszItem)
|
|
{
|
|
HRESULT hrErr = ResultFromScode(MK_E_NOOBJECT);
|
|
IOleObject *pOleObj = NULL;
|
|
PIBPart pPart;
|
|
if (SUCCEEDED(pDoc->GetPart(&pPart, lpszItem))) {
|
|
|
|
IUnknown *pUnk = pPart;
|
|
// check for link to embedding case!
|
|
// if so, get the IOleObject out of the Bolero helper and use that!
|
|
BOlePart *pBOlePart;
|
|
if (SUCCEEDED(pUnk->QueryInterface(IID_BOlePart, &(LPVOID)pBOlePart))) {
|
|
if (pBOlePart->pOleObject) {
|
|
pUnk = pBOlePart->pOleObject;
|
|
}
|
|
pBOlePart->Release();
|
|
}
|
|
|
|
if (SUCCEEDED(pUnk->QueryInterface(IID_IOleObject,&(LPVOID)pOleObj))) {
|
|
hrErr = OleIsRunning(pOleObj)
|
|
? NOERROR
|
|
: ResultFromScode(S_FALSE);
|
|
pOleObj->Release();
|
|
pOleObj = NULL;
|
|
}
|
|
pPart->Release();
|
|
}
|
|
return hrErr;
|
|
}
|
|
|
|
//**************************************************************************
|
|
//
|
|
// IPersistFile implementation
|
|
//
|
|
//**************************************************************************
|
|
|
|
HRESULT _IFUNC BOleContainer::Load (LPCOLESTR lpszFileName, DWORD grfMode)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
hr = pDoc->Init(lpszFileName);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT _IFUNC BOleContainer::Save (LPCOLESTR lpszFileName, BOOL fRemember)
|
|
{
|
|
return ResultFromScode (E_NOTIMPL);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleContainer::SaveCompleted (LPCOLESTR lpszFileName)
|
|
{
|
|
return ResultFromScode (E_NOTIMPL);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleContainer::GetCurFile (LPOLESTR FAR* lplpszFileName)
|
|
{
|
|
return ResultFromScode (E_NOTIMPL);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleContainer::OnRename(PIBLinkable pContainer, LPCOLESTR pszName)
|
|
{
|
|
HRESULT hr;
|
|
LPMONIKER pMon;
|
|
|
|
if (pszName) {
|
|
LPMONIKER pmkDoc = NULL;
|
|
if (pContainer && SUCCEEDED(pContainer->GetMoniker(&pmkDoc))) {
|
|
// intermediate moniker
|
|
LPMONIKER pmkObj = NULL;
|
|
|
|
if (SUCCEEDED(CreateItemMoniker(TEXT("!"), (LPOLESTR)pszName, &pmkObj))) {
|
|
hr = CreateGenericComposite(pmkDoc, pmkObj, &pMon);
|
|
pmkObj->Release();
|
|
}
|
|
pmkDoc->Release();
|
|
}
|
|
else {
|
|
// root moniker
|
|
hr = OLE::CreateFileMoniker ((LPOLESTR)pszName, &pMon);
|
|
}
|
|
}
|
|
else
|
|
pMon = NULL;
|
|
|
|
hr = SetMoniker (pMon);
|
|
if (pMon)
|
|
pMon->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//**************************************************************************
|
|
//
|
|
// IBLinkable implementation
|
|
//
|
|
//**************************************************************************
|
|
|
|
HRESULT _IFUNC BOleContainer::Init( PIBContains pC, LPCOLESTR pszProgId)
|
|
{
|
|
pDoc = pC;
|
|
pFactory->GetService()->FindClassFactory( pszProgId, &pClassFact);
|
|
return pClassFact ? NOERROR : ResultFromScode (E_FAIL);
|
|
}
|
|
|
|
HRESULT _IFUNC BOleContainer::SetMoniker(LPMONIKER pMon)
|
|
{
|
|
HRESULT hr;
|
|
// get the running object table
|
|
LPRUNNINGOBJECTTABLE pROT = NULL;
|
|
hr = OLE::GetRunningObjectTable (0, &pROT);
|
|
if (SUCCEEDED(hr)) {
|
|
// Register the new moniker BEFORE revoking the old moniker.
|
|
// Otherwise the object's "StubManager" gets hosed.
|
|
//
|
|
DWORD oldRegId = regId;
|
|
|
|
if (pMoniker) {
|
|
pMoniker->Release();
|
|
pMoniker = NULLP;
|
|
}
|
|
// Store the new moniker if any
|
|
if (pMon) {
|
|
pMoniker = pMon;
|
|
pMoniker->AddRef();
|
|
|
|
// Register in the running object table
|
|
//
|
|
hr = pROT->Register (0, //ROTFLAGS_REGISTRATIONKEEPSALIVE,
|
|
AsPIUnknown(pObjOuter), pMoniker, ®Id);
|
|
}
|
|
else
|
|
regId = 0L;
|
|
|
|
// release any old monikers and running object table registration
|
|
if (oldRegId != 0L) {
|
|
pROT->Revoke(oldRegId);
|
|
oldRegId = 0L;
|
|
}
|
|
pROT->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT _IFUNC BOleContainer::GetMoniker(LPMONIKER *ppMon)
|
|
{
|
|
HRESULT hrErr = ResultFromScode (E_FAIL);
|
|
if (pMoniker) {
|
|
pMoniker->AddRef();
|
|
*ppMon = pMoniker;
|
|
hrErr = NOERROR;
|
|
}
|
|
else {
|
|
// Must be a nested embedding. Ask the container for one.
|
|
|
|
IOleObject *pOleObj;
|
|
if (SUCCEEDED(QueryInterface(IID_IOleObject, &(LPVOID)pOleObj))) {
|
|
hrErr = pOleObj->GetMoniker(OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_OBJFULL, ppMon);
|
|
pOleObj->Release();
|
|
}
|
|
}
|
|
return hrErr;
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//
|
|
|
|
|
|
|