- 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>
426 lines
13 KiB
C++
426 lines
13 KiB
C++
/* Borland C++ - (C) Copyright 1994 by Borland International */
|
|
|
|
/***************************************************************************
|
|
|
|
Program Name DDEClnt.c
|
|
|
|
Purpose A simple DDE client application, which communicates
|
|
to a DDE server using the new 3.1 api DDEML calls.
|
|
|
|
To use this program, build DDEClnt and DDESrvr. There
|
|
are project files for this. From the DDEClnt, connect
|
|
to the server, and send pre-formatted messages to the
|
|
the server, and request messages from the server.
|
|
Disconnect before closing app.
|
|
|
|
****************************************************************************/
|
|
|
|
#define STRICT
|
|
|
|
#include <windows.h>
|
|
#pragma hdrstop
|
|
#include <ddeml.h>
|
|
#include <dde.h>
|
|
#include <windowsx.h>
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "ddeclnt.h"
|
|
|
|
|
|
HANDLE hInst; /* Current instance of application */
|
|
HWND hWnd; /* Handle of Main window */
|
|
|
|
int xScreen; /* Screen metrics */
|
|
int yScreen; /* ... */
|
|
int yFullScreen; /* ... */
|
|
int xFrame; /* ... */
|
|
int yMenu; /* ... */
|
|
TEXTMETRIC tm; /* Text metrics */
|
|
int cxChar; /* Character metrics */
|
|
int cyChar; /* ... */
|
|
|
|
char szScreenText[10][80]; /* Contains 10 lines of display data*/
|
|
int cCurrentLine; /* Index into szScreenText */
|
|
int cTotalLines; /* Total lines in szScreenText */
|
|
|
|
/*
|
|
The DDE variables
|
|
*/
|
|
|
|
DWORD idInst = 0L; /* Instance of app for DDEML */
|
|
FARPROC lpDdeProc; /* DDE callback function */
|
|
HSZ hszService;
|
|
HSZ hszTopic;
|
|
HSZ hszItem;
|
|
HCONV hConv = (HCONV)NULL; /*Handle of established conversation*/
|
|
HDDEDATA hData;
|
|
DWORD dwResult;
|
|
WORD wFmt = CF_TEXT; /* Clipboard format */
|
|
char szDDEString[80]; /* Local allocation of data buffer */
|
|
char szDDEData[80]; /* Local receive data buffer */
|
|
int iClientCount = 0; /* Client to Server message counter*/
|
|
char tbuf[5]; /* Temporary, to hold count */
|
|
|
|
char szAppName[] = "DDEClientApplication";
|
|
|
|
|
|
/***************************************************************************/
|
|
#pragma argsused
|
|
int PASCAL WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|
LPSTR lpszCmdLine, int nCmdShow )
|
|
{
|
|
MSG msg;
|
|
|
|
|
|
if ( !hPrevInstance ) /* Other instances of app running? */
|
|
if ( !InitApplication ( hInstance ) ) /* Initialize shared things */
|
|
return ( FALSE ); /* Exits if unable to initialize */
|
|
|
|
if ( !InitInstance ( hInstance, nCmdShow ) )
|
|
return ( FALSE );
|
|
|
|
while ( GetMessage ( &msg, NULL, 0, 0 ) )
|
|
{
|
|
TranslateMessage ( &msg );
|
|
DispatchMessage ( &msg );
|
|
}
|
|
|
|
DdeUninitialize ( idInst );
|
|
|
|
return ( msg.wParam );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
BOOL FAR PASCAL InitApplication ( HANDLE hInstance )
|
|
{
|
|
WNDCLASS wc;
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpfnWndProc = MainWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = hInstance;
|
|
wc.hIcon = LoadIcon ( hInstance, "DDEClientIcon" );
|
|
wc.hCursor = LoadCursor ( NULL, IDC_ARROW );
|
|
wc.hbrBackground = GetStockObject ( WHITE_BRUSH );
|
|
wc.lpszMenuName = "DDEClientMenu";
|
|
wc.lpszClassName = szAppName;
|
|
|
|
if ( !RegisterClass ( &wc ) )
|
|
return ( FALSE );
|
|
|
|
return ( TRUE );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
BOOL InitInstance ( HANDLE hInstance, int nCmdShow )
|
|
{
|
|
hInst = hInstance;
|
|
|
|
xScreen = GetSystemMetrics ( SM_CXSCREEN );
|
|
yScreen = GetSystemMetrics ( SM_CYSCREEN );
|
|
|
|
hWnd = CreateWindow ( szAppName,
|
|
"DDE Client Window",
|
|
WS_OVERLAPPEDWINDOW,
|
|
10, /* These co-ordinates look */
|
|
10, /* good on a VGA monitor */
|
|
xScreen - 200, /* running in 640x480. No */
|
|
yScreen / 2 - 50, /* combination was tried. */
|
|
NULL,
|
|
NULL,
|
|
hInstance,
|
|
NULL );
|
|
|
|
/*
|
|
If window could not be created, return "failure"
|
|
*/
|
|
|
|
if ( !hWnd )
|
|
return ( FALSE );
|
|
|
|
/*
|
|
Make the window visible; update its client area; and return "success"
|
|
*/
|
|
|
|
ShowWindow ( hWnd, nCmdShow ); /* Show the window */
|
|
UpdateWindow ( hWnd ); /* Sends WM_PAINT message */
|
|
return ( TRUE ); /* Returns the value from PostQuitMessage */
|
|
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
#pragma warn -eff
|
|
LRESULT CALLBACK _export MainWndProc ( HWND hWnd, UINT message,
|
|
WPARAM wParam, LPARAM lParam )
|
|
{
|
|
HDC hDC;
|
|
PAINTSTRUCT ps;
|
|
DLGPROC dlgProcAbout;
|
|
int i;
|
|
int j;
|
|
int y;
|
|
|
|
|
|
switch ( message )
|
|
{
|
|
case WM_CREATE:
|
|
hDC = GetDC ( hWnd );
|
|
|
|
GetTextMetrics ( hDC, &tm );
|
|
cxChar = tm.tmAveCharWidth;
|
|
cyChar = tm.tmHeight + tm.tmExternalLeading;
|
|
|
|
ReleaseDC ( hWnd, hDC );
|
|
|
|
lpDdeProc = MakeProcInstance ( (FARPROC) DDECallback, hInst );
|
|
if ( DdeInitialize ( (LPDWORD)&idInst, (PFNCALLBACK)lpDdeProc,
|
|
APPCMD_CLIENTONLY, 0L ) )
|
|
{
|
|
HandleOutput ( "Client DDE initialization failure." );
|
|
return ( FALSE );
|
|
}
|
|
|
|
hszService = DdeCreateStringHandle ( idInst, "Borland", CP_WINANSI );
|
|
hszTopic = DdeCreateStringHandle ( idInst, "DDEExample", CP_WINANSI );
|
|
hszItem = DdeCreateStringHandle ( idInst, "DDEData", CP_WINANSI );
|
|
|
|
cCurrentLine = 0;
|
|
cTotalLines = 0;
|
|
|
|
strcpy ( szDDEString, "Client application message number: " );
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch ( GET_WM_COMMAND_ID(wParam, lParam) )
|
|
{
|
|
case IDM_EXIT:
|
|
DestroyWindow ( hWnd );
|
|
break;
|
|
|
|
case IDM_CONNECT_SERVER:
|
|
if ( hConv == (HCONV)NULL )
|
|
{
|
|
hConv = DdeConnect ( idInst, hszService, hszTopic,
|
|
(PCONVCONTEXT) NULL );
|
|
if ( hConv == (HCONV)NULL )
|
|
{
|
|
HandleError ( DdeGetLastError ( idInst ) );
|
|
HandleOutput ( "Unsuccessful connection." );
|
|
}
|
|
else
|
|
HandleOutput ( "Successful connection." );
|
|
}
|
|
else
|
|
HandleOutput ( "Already connected to DDE Server." );
|
|
|
|
break;
|
|
|
|
case IDM_DISCONNECT_SERVER:
|
|
if ( hConv != (HCONV)NULL )
|
|
{
|
|
DdeDisconnect ( hConv );
|
|
hConv = (HCONV)NULL;
|
|
HandleOutput ( "Disconnected from server." );
|
|
}
|
|
else
|
|
HandleOutput ( "Must be connected before disconnecting." );
|
|
|
|
break;
|
|
|
|
case IDM_MSG_TO_SERVER:
|
|
if ( hConv != (HCONV)NULL )
|
|
{
|
|
iClientCount ++;
|
|
sprintf ( tbuf, "%3d.", iClientCount );
|
|
strncpy ( &szDDEString[36], tbuf, 5 );
|
|
|
|
#if defined(__WIN32__)
|
|
hData = DdeCreateDataHandle ( idInst, (LPBYTE) szDDEString,
|
|
#else
|
|
hData = DdeCreateDataHandle ( idInst, szDDEString,
|
|
#endif
|
|
sizeof ( szDDEString ), 0L, hszItem, wFmt, 0 );
|
|
|
|
if ( hData != (HDDEDATA)NULL )
|
|
hData = DdeClientTransaction ( (LPBYTE)hData, -1, hConv,
|
|
hszItem, wFmt, XTYP_POKE, 1000, &dwResult );
|
|
else
|
|
HandleOutput ( "Could not create data handle." );
|
|
}
|
|
else
|
|
HandleOutput ( "A connection to a DDE Server has not been established." );
|
|
|
|
break;
|
|
|
|
case IDM_MSG_FROM_SERVER:
|
|
if ( hConv != (HCONV)NULL )
|
|
{
|
|
hData = DdeClientTransaction ( NULL, 0, hConv,
|
|
hszItem, wFmt, XTYP_REQUEST, 1000, &dwResult );
|
|
|
|
if ( dwResult == DDE_FNOTPROCESSED )
|
|
HandleOutput ( "Data not available from server." );
|
|
else
|
|
{
|
|
DdeGetData ( hData, (LPBYTE) szDDEData, 80L, 0L );
|
|
|
|
if ( szDDEData != NULL )
|
|
HandleOutput ( szDDEData );
|
|
else
|
|
HandleOutput ( "Message from server is null." );
|
|
}
|
|
}
|
|
else
|
|
HandleOutput ( "A connection to a DDE Server has not been established." );
|
|
|
|
break;
|
|
|
|
case IDM_ABOUT:
|
|
dlgProcAbout = (DLGPROC) MakeProcInstance ( (FARPROC)About, hInst );
|
|
DialogBox ( hInst, "AboutBox", hWnd, dlgProcAbout );
|
|
FreeProcInstance ( (FARPROC) dlgProcAbout );
|
|
break;
|
|
|
|
default:
|
|
return ( DefWindowProc ( hWnd, message, wParam, lParam ) );
|
|
}
|
|
break;
|
|
|
|
case WM_PAINT:
|
|
hDC = BeginPaint ( hWnd, &ps );
|
|
|
|
y = 0;
|
|
|
|
for ( i = 0; i < cTotalLines; i ++ )
|
|
{
|
|
if ( cTotalLines == 8 )
|
|
j = ( (cCurrentLine + 1 + i) % 9 );
|
|
else
|
|
j = i; // can't do this if we clear window and start in middle of array
|
|
|
|
TextOut ( hDC, 0, y, (LPSTR)(szScreenText[j]),
|
|
lstrlen ( szScreenText[j] ) );
|
|
y = y + cyChar;
|
|
}
|
|
|
|
EndPaint ( hWnd, &ps );
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
if ( hConv != (HCONV)NULL )
|
|
{
|
|
DdeDisconnect ( hConv );
|
|
hConv = (HCONV)NULL;
|
|
}
|
|
|
|
DdeFreeStringHandle ( idInst, hszService );
|
|
DdeFreeStringHandle ( idInst, hszTopic );
|
|
DdeFreeStringHandle ( idInst, hszItem );
|
|
|
|
FreeProcInstance ( lpDdeProc );
|
|
|
|
PostQuitMessage ( 0 );
|
|
break;
|
|
|
|
default:
|
|
return ( DefWindowProc ( hWnd, message, wParam, lParam ) );
|
|
}
|
|
|
|
return ( FALSE );
|
|
}
|
|
#pragma warn .eff
|
|
|
|
/***************************************************************************/
|
|
|
|
#pragma argsused
|
|
BOOL CALLBACK About ( HWND hDlg, UINT message,
|
|
WPARAM wParam, LPARAM lParam )
|
|
{
|
|
switch ( message )
|
|
{
|
|
case WM_INITDIALOG: /* message: initialize dialog box */
|
|
return ( TRUE );
|
|
|
|
case WM_COMMAND: /* message: received a command */
|
|
if ( GET_WM_COMMAND_ID(wParam, lParam) == IDOK ||
|
|
GET_WM_COMMAND_ID(wParam, lParam) == IDCANCEL )
|
|
{
|
|
EndDialog ( hDlg, TRUE ); /* Exits the dialog box */
|
|
return ( TRUE );
|
|
}
|
|
break;
|
|
}
|
|
return ( FALSE ); /* Didn't process a message */
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
#pragma argsused
|
|
HDDEDATA EXPENTRY _export DDECallback ( WORD wType, WORD wFmt, HCONV hConvX, HSZ hsz1,
|
|
HSZ hsz2, HDDEDATA hData, DWORD dwData1,
|
|
DWORD dwData2 )
|
|
{
|
|
switch ( wType )
|
|
{
|
|
case XTYP_DISCONNECT:
|
|
hConv = (HCONV)NULL;
|
|
HandleOutput ( "The server forced a disconnect." );
|
|
return ( (HDDEDATA) NULL );
|
|
|
|
case XTYP_ERROR:
|
|
break;
|
|
|
|
case XTYP_XACT_COMPLETE:
|
|
// compare transaction identifier, indicate transaction complete
|
|
break;
|
|
|
|
}
|
|
|
|
return ( (HDDEDATA) NULL );
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
void HandleError ( DWORD DdeError )
|
|
{
|
|
switch ( DdeError )
|
|
{
|
|
case DMLERR_DLL_NOT_INITIALIZED:
|
|
HandleOutput ( "DLL not initialized." );
|
|
break;
|
|
|
|
case DMLERR_INVALIDPARAMETER:
|
|
HandleOutput ( "Invalid parameter." );
|
|
break;
|
|
|
|
case DMLERR_NO_CONV_ESTABLISHED:
|
|
HandleOutput ( "No conversation established." );
|
|
break;
|
|
|
|
case DMLERR_NO_ERROR:
|
|
HandleOutput ( "No error." );
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
void HandleOutput ( char *szOutputString )
|
|
{
|
|
strcpy ( szScreenText[cCurrentLine], szOutputString );
|
|
cCurrentLine = ( cCurrentLine + 1 ) % 9;
|
|
|
|
if ( cTotalLines < 8 )
|
|
cTotalLines++;
|
|
|
|
InvalidateRect ( hWnd, NULL, TRUE );
|
|
UpdateWindow ( hWnd );
|
|
}
|
|
|