- 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>
360 lines
12 KiB
C++
360 lines
12 KiB
C++
// Borland C++ - (C) Copyright 1991, 1992 by Borland International
|
|
|
|
//*******************************************************************
|
|
//
|
|
// program - DDESrvr.c
|
|
// purpose - DDE server interface routines. This file is part of the
|
|
// MSGWND project.
|
|
//
|
|
//*******************************************************************
|
|
|
|
#define STRICT
|
|
#include <windows.h>
|
|
#pragma hdrstop
|
|
#include <dde.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <windowsx.h>
|
|
|
|
#include "ddepack.h"
|
|
#include "ddesrvr.h"
|
|
|
|
# define WW_CLIENT 0
|
|
# define ACK 0x8000
|
|
# define BUSY 0x4000
|
|
|
|
#if defined(__WIN32__)
|
|
#define SetWindowClient(hWnd,hWndClient)\
|
|
SetWindowLong (hWnd, WW_CLIENT, (LONG) (hWndClient))
|
|
#define GetWindowClient(hWnd)\
|
|
((HWND) GetWindowLong (hWnd, WW_CLIENT))
|
|
#define DDEGetCommandHandle(hCommand)\
|
|
((LPARAM)(hCommand))
|
|
#else
|
|
#define SetWindowClient(hWnd,hWndClient)\
|
|
SetWindowWord (hWnd, WW_CLIENT, (WORD) (hWndClient))
|
|
#define GetWindowClient(hWnd)\
|
|
((HWND) GetWindowWord (hWnd, WW_CLIENT))
|
|
#define DDEGetCommandHandle(hCommand)\
|
|
((LPARAM)HIWORD(hCommand))
|
|
#endif
|
|
|
|
static int nServerClassRegistered;
|
|
static char szServerClass[] = "ddeserver";
|
|
static WORD wLastDDEServerMsg;
|
|
|
|
//*******************************************************************
|
|
// DDEServerInit - called in response to WM_DDE_INITIATE
|
|
//
|
|
// paramaters:
|
|
// hParentWnd - The handle of the server window trying to
|
|
// respond to this dde conversation.
|
|
// hClientWnd - The handle of the client window trying to start
|
|
// this dde conversation.
|
|
// lParam - lParam send by client window.
|
|
// Contains atoms of application and topic client
|
|
// wants to talk about.
|
|
// szApp - The name of the application server represents.
|
|
// szTopic - The name of the topic server knows about.
|
|
//
|
|
// returns:
|
|
// The handle of the channel to use to continue the conversation
|
|
// or
|
|
// NULL if conversation could not be opened.
|
|
//
|
|
//*******************************************************************
|
|
HWND DDEServerInit(HWND hParentWnd, HWND hClientWnd, LPARAM lParam,
|
|
char *szApp, char *szTopic)
|
|
{
|
|
HINSTANCE hInst;
|
|
HWND hChannel;
|
|
ATOM aApp;
|
|
ATOM aTopic;
|
|
WNDCLASS wclass;
|
|
char szClassName[sizeof(szServerClass) + 10];
|
|
|
|
// Get atoms representing application and topic we will talk about.
|
|
aApp = GlobalAddAtom(szApp);
|
|
if (!aApp)
|
|
return(0);
|
|
|
|
aTopic = GlobalAddAtom(szTopic);
|
|
if (!aTopic)
|
|
{
|
|
GlobalDeleteAtom(aApp);
|
|
return(0);
|
|
}
|
|
|
|
// If request is not for application and topic we will talk about
|
|
// do not open conversaton.
|
|
if ((aApp != LOWORD(lParam)) || (aTopic != HIWORD(lParam)))
|
|
{
|
|
GlobalDeleteAtom(aApp);
|
|
GlobalDeleteAtom(aTopic);
|
|
return(0);
|
|
}
|
|
|
|
// Get parents instance to use in creating window to carry on
|
|
// dde conversation.
|
|
hInst = (HANDLE)GetWindowInstance(hParentWnd);
|
|
if (!hInst)
|
|
return(0);
|
|
|
|
// Create a unique class name for this instance of the server.
|
|
sprintf(szClassName, "%s%04X", szServerClass, hInst);
|
|
|
|
// If we have not already done it, register the window class to
|
|
// carry on this conversation.
|
|
if (!nServerClassRegistered)
|
|
{
|
|
wclass.style = CS_HREDRAW | CS_VREDRAW;
|
|
wclass.lpfnWndProc = DDEServerWndProc;
|
|
wclass.cbClsExtra = 0;
|
|
wclass.cbWndExtra = 2;
|
|
wclass.hInstance = hInst;
|
|
wclass.hIcon = 0;
|
|
wclass.hCursor = 0;
|
|
wclass.hbrBackground = 0;
|
|
wclass.lpszMenuName = 0;
|
|
wclass.lpszClassName = szClassName;
|
|
|
|
// Do not fail if register fails, because another app may have
|
|
// already registered this class.
|
|
RegisterClass(&wclass);
|
|
|
|
// So we won't try to register again.
|
|
nServerClassRegistered = 1;
|
|
}
|
|
|
|
// Create the window that will remain hidden but will carry on the
|
|
// conversation wih the dde client.
|
|
hChannel = CreateWindow(szClassName, // window class name
|
|
NULL, // window title
|
|
WS_CHILD, // window style
|
|
CW_USEDEFAULT, // window origin
|
|
0,
|
|
CW_USEDEFAULT, // window size
|
|
0,
|
|
hParentWnd, // window parent
|
|
NULL, // window id
|
|
hInst, // window instance
|
|
NULL); // no parms
|
|
|
|
// If create of window failed we cannot continue.
|
|
if (!hChannel)
|
|
return(0);
|
|
|
|
// Remember the handle of our client.
|
|
SetWindowClient(hChannel, hClientWnd);
|
|
|
|
// Send acknowledgement to client.
|
|
wLastDDEServerMsg = WM_DDE_ACK;
|
|
SendMessage(hClientWnd,
|
|
(UINT)wLastDDEServerMsg,
|
|
(WPARAM)hChannel,
|
|
(LPARAM)DDEPack(WM_DDE_ACK, aApp, aTopic));
|
|
|
|
// Return handle of window that will carry on the conversation for
|
|
// this server.
|
|
return(hChannel);
|
|
}
|
|
|
|
//*******************************************************************
|
|
// DDEServerClose - close the dde conversation with a client
|
|
//
|
|
// paramaters:
|
|
// hChannel - The handle of the window conducting
|
|
// the dde conversation.
|
|
//
|
|
//*******************************************************************
|
|
int DDEServerClose(HWND hChannel)
|
|
{
|
|
HWND hClientWnd;
|
|
|
|
// If the channel is still active.
|
|
if (IsWindow(hChannel))
|
|
{
|
|
wLastDDEServerMsg = WM_DDE_TERMINATE;
|
|
|
|
// Get handle of client we were conversing with.
|
|
hClientWnd = (HWND)GetWindowClient(hChannel);
|
|
|
|
// If he is still active.
|
|
if (IsWindow(hClientWnd))
|
|
SendMessage(hClientWnd, (UINT)wLastDDEServerMsg, (WPARAM)hChannel, (LPARAM)0L);
|
|
}
|
|
|
|
return(1);
|
|
}
|
|
|
|
//*******************************************************************
|
|
// DDEServerWndProc - window proc to manage interface with client
|
|
//
|
|
// paramaters:
|
|
// hWnd - The window handle for this message
|
|
// message - The message number
|
|
// wParam - The WPARAM parameter for this message
|
|
// lParam - The LPARAM parameter for this message
|
|
//
|
|
// returns:
|
|
// depends on message.
|
|
//
|
|
//*******************************************************************
|
|
LRESULT CALLBACK _export DDEServerWndProc(HWND hWnd, UINT message,
|
|
WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WORD wStatus;
|
|
HWND hClientWnd;
|
|
HANDLE hCommand;
|
|
HANDLE hData;
|
|
LPSTR lpData;
|
|
HANDLE hShData;
|
|
DDEDATA FAR *lpShData;
|
|
char szItem[30];
|
|
ATOM aItem;
|
|
LPSTR lpCommand;
|
|
int nRc;
|
|
int nSize;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_DDE_EXECUTE: // execute a command for client
|
|
// Get handle of client.
|
|
hClientWnd = (HWND)wParam;
|
|
|
|
// Init status.
|
|
wStatus = 0;
|
|
|
|
// Get handle of command client is sending us.
|
|
hCommand = (HANDLE)DDEGetCommandHandle(lParam);
|
|
|
|
// Lock it down to get address.
|
|
lpCommand = GlobalLock(hCommand);
|
|
if (lpCommand)
|
|
{
|
|
// Call our function to execute the command.
|
|
if (DDEExecuteCommand(lpCommand))
|
|
wStatus = ACK;
|
|
|
|
GlobalUnlock(hCommand);
|
|
}
|
|
|
|
// Send acknowledgement back to client.
|
|
PostMessage(hClientWnd, WM_DDE_ACK, (WPARAM)hWnd,
|
|
DDEPack (WM_DDE_ACK, (UINT)wStatus, (UINT)hCommand));
|
|
break;
|
|
|
|
case WM_DDE_REQUEST: // data request from a client
|
|
// Get handle of client.
|
|
hClientWnd = (HWND)wParam;
|
|
|
|
// Get atom representing data request item.
|
|
aItem = HIWORD(lParam);
|
|
if (!GlobalGetAtomName(aItem, szItem, sizeof(szItem)))
|
|
{
|
|
// Error if atom not found.
|
|
PostMessage(hClientWnd, WM_DDE_ACK, (WPARAM)hWnd,
|
|
(LPARAM)DDEPack(WM_DDE_ACK, 0, aItem));
|
|
return(0L);
|
|
}
|
|
|
|
// Init return code.
|
|
nRc = 0;
|
|
|
|
// Don't care about case.
|
|
strupr(szItem);
|
|
|
|
// Call our function to get the data item.
|
|
nSize = DDEData(szItem, &hData);
|
|
|
|
// If any data found.
|
|
if (nSize)
|
|
{
|
|
// Get shared memory to send item back in.
|
|
hShData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT | GMEM_DDESHARE,
|
|
(DWORD) (nSize + sizeof(DDEDATA) + 1));
|
|
if (hShData)
|
|
{
|
|
// Lock it down to get address.
|
|
lpShData = (DDEDATA FAR *) GlobalLock(hShData);
|
|
if (lpShData)
|
|
{
|
|
// Setup data header.
|
|
lpShData->fResponse = 1;
|
|
lpShData->fRelease = 1;
|
|
lpShData->fAckReq = 0;
|
|
lpShData->cfFormat = CF_TEXT;
|
|
|
|
// Lock out local copy of data to get address.
|
|
lpData = GlobalLock(hData);
|
|
if (lpData)
|
|
{
|
|
// Copy data to shared memory.
|
|
#if defined(__WIN32__)
|
|
strcpy((LPSTR)lpShData->Value, lpData);
|
|
#else
|
|
_fstrcpy((LPSTR)lpShData->Value, lpData);
|
|
#endif
|
|
GlobalUnlock(hData);
|
|
|
|
nRc = 1;
|
|
}
|
|
|
|
GlobalUnlock(hShData);
|
|
}
|
|
}
|
|
|
|
GlobalFree(hData);
|
|
}
|
|
|
|
if (nRc)
|
|
{
|
|
// If ok send data back.
|
|
PostMessage(hClientWnd, WM_DDE_DATA, (WPARAM)hWnd,
|
|
(LPARAM)DDEPack (WM_DDE_DATA, (UINT)hShData, (UINT)aItem));
|
|
}
|
|
else
|
|
{
|
|
// If errors just send negative acknowlegement back.
|
|
PostMessage(hClientWnd, WM_DDE_ACK, (WPARAM)hWnd,
|
|
(LPARAM)DDEPack (WM_DDE_ACK, 0, aItem));
|
|
}
|
|
break;
|
|
|
|
case WM_DDE_TERMINATE: // server says terminate conversation
|
|
// Get handle of client we are dealing with.
|
|
hClientWnd = (HWND)GetWindowClient(hWnd);
|
|
|
|
// Ignore if not from our client.
|
|
if (wParam != (WPARAM)hClientWnd)
|
|
return(0L);
|
|
|
|
// Forget who client is.
|
|
SetWindowClient(hWnd, 0);
|
|
|
|
// Tell our parent conversation closed.
|
|
SendMessage(GetParent(hWnd), WMU_DDE_CLOSED, (WPARAM)hWnd, 0L);
|
|
|
|
// Send terminate to server to acknowledge we recieved
|
|
// terminate, if we did not initiate the termination ourselves.
|
|
if ((wLastDDEServerMsg != WM_DDE_TERMINATE) && IsWindow(hClientWnd))
|
|
PostMessage(hClientWnd, WM_DDE_TERMINATE, (WPARAM)hWnd, 0L);
|
|
|
|
// Terminate this child window.
|
|
DestroyWindow(hWnd);
|
|
break;
|
|
|
|
case WM_DESTROY: // destroy this window
|
|
// Terminate any ongoing conversation on our way out.
|
|
DDEServerClose(hWnd);
|
|
break;
|
|
|
|
default:
|
|
return(DefWindowProc(hWnd, message, wParam, lParam));
|
|
}
|
|
|
|
return(0L);
|
|
}
|
|
|
|
//*******************************************************************
|