- 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>
1032 lines
30 KiB
C++
1032 lines
30 KiB
C++
// Borland C++ - (C) Copyright 1991, 1992 by Borland International
|
|
|
|
//*******************************************************************
|
|
//
|
|
// program - Msgwnd.c
|
|
// purpose - A windows program to receive and display messages.
|
|
// This illustrates how DDE messages can be sent from
|
|
// one application and received by another.
|
|
//
|
|
// To use this program, build MSGWND and TSTAPP. There
|
|
// are project files for this. When you run TSTAPP, MSGWND
|
|
// will be started automatically.
|
|
//
|
|
//*******************************************************************
|
|
|
|
#define STRICT
|
|
#include <windows.h>
|
|
#include <dde.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <bios.h>
|
|
#include <ctype.h>
|
|
#include <io.h>
|
|
#include <dos.h>
|
|
#include <windowsx.h>
|
|
|
|
#include "msgwnd.h"
|
|
#include "msgproc.h"
|
|
#include "ddesrvr.h"
|
|
|
|
#define MAX_QRT_LEN 100
|
|
|
|
typedef struct scrollkeys
|
|
{
|
|
WORD wVirtkey;
|
|
int iMessage;
|
|
WORD wRequest;
|
|
} SCROLLKEYS;
|
|
|
|
SCROLLKEYS key2scroll [] =
|
|
{
|
|
{ VK_HOME, WM_COMMAND, IDM_HOME },
|
|
{ VK_END, WM_VSCROLL, SB_BOTTOM },
|
|
{ VK_PRIOR, WM_VSCROLL, SB_PAGEUP },
|
|
{ VK_NEXT, WM_VSCROLL, SB_PAGEDOWN },
|
|
{ VK_UP, WM_VSCROLL, SB_LINEUP },
|
|
{ VK_DOWN, WM_VSCROLL, SB_LINEDOWN },
|
|
{ VK_LEFT, WM_HSCROLL, SB_PAGEUP },
|
|
{ VK_RIGHT, WM_HSCROLL, SB_PAGEDOWN }
|
|
};
|
|
|
|
# define NUMKEYS (sizeof key2scroll / sizeof key2scroll[0])
|
|
|
|
// data initialized by first instance
|
|
typedef struct tagSETUPDATA
|
|
{
|
|
char szAppName[10]; // name of application
|
|
} SETUPDATA;
|
|
|
|
SETUPDATA SetUpData;
|
|
|
|
// Data that can be referenced throughout the
|
|
// program but not passed to other instances
|
|
|
|
HINSTANCE hInst; // hInstance of application
|
|
HWND hWndMain; // hWnd of main window
|
|
|
|
int xChar, yChar, yCharnl;
|
|
int xClient, yClient;
|
|
|
|
LOGFONT cursfont;
|
|
HFONT holdsfont;
|
|
HFONT hnewsfont;
|
|
|
|
RECT wrect;
|
|
|
|
// window scroll/paint stuff
|
|
int nVscrollMax, nHscrollMax;
|
|
int nVscrollPos, nHscrollPos;
|
|
int numlines;
|
|
int maxwidth;
|
|
int nVscrollInc, nHscrollInc;
|
|
int nPaintBeg, nPaintEnd;
|
|
int nPageMaxLines;
|
|
int plines;
|
|
|
|
// for scroll print
|
|
RECT rect;
|
|
int blanklen;
|
|
char blanks[256];
|
|
|
|
// to keep lines
|
|
# define MAX_KEEP 50
|
|
HANDLE hkeep[MAX_KEEP + 1];
|
|
int hwm_keep;
|
|
|
|
// function prototypes
|
|
|
|
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|
LPSTR lpszCmdLine, int cmdShow);
|
|
|
|
BOOL InitMsgwnd(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|
LPSTR lpszCmdLine, int cmdShow);
|
|
BOOL InitMsgwndFirst(HINSTANCE hInstance);
|
|
BOOL InitMsgwndEvery(HINSTANCE hInstance, int cmdShow);
|
|
void CloseMsgwnd(HWND hWnd);
|
|
BOOL CALLBACK _export About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
|
|
|
|
LRESULT CALLBACK _export MsgwndWndProc(HWND hWnd, UINT message,
|
|
WPARAM wParam, LPARAM lParam);
|
|
|
|
void SetupScroll(HWND hWnd);
|
|
void MsgwndPaint(HWND hWnd);
|
|
void ScrollPrint(HWND hWnd, char *str);
|
|
void ClearKeep(void);
|
|
|
|
//*******************************************************************
|
|
// WinMain - Msgwnd main
|
|
//
|
|
// paramaters:
|
|
// hInstance - The instance of this instance of this
|
|
// application.
|
|
// hPrevInstance - The instance of the previous instance
|
|
// of this application. This will be 0
|
|
// if this is the first instance.
|
|
// lpszCmdLine - A long pointer to the command line that
|
|
// started this application.
|
|
// cmdShow - Indicates how the window is to be shown
|
|
// initially. ie. SW_SHOWNORMAL, SW_HIDE,
|
|
// SW_MIMIMIZE.
|
|
//
|
|
// returns:
|
|
// wParam from last message.
|
|
//
|
|
//*******************************************************************
|
|
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|
LPSTR lpszCmdLine, int cmdShow)
|
|
{
|
|
MSG msg;
|
|
BOOL brc;
|
|
|
|
brc = InitMsgwnd(hInstance, hPrevInstance, lpszCmdLine, cmdShow);
|
|
if (brc == FALSE)
|
|
return(0);
|
|
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
return(msg.wParam);
|
|
}
|
|
|
|
#if !defined(__WIN32__)
|
|
//*******************************************************************
|
|
// InitMsgwndAdded - done only for added instances of Msgwnd
|
|
//
|
|
// paramaters:
|
|
// hPrevInstance - The instance of the previous instance
|
|
// of this application.
|
|
//
|
|
// returns:
|
|
// FALSE to indicate multiple instances are not allowed.
|
|
//
|
|
//*******************************************************************
|
|
BOOL InitMsgwndAdded(HINSTANCE hPrevInstance)
|
|
{
|
|
// get the results of the initialization of first instance
|
|
GetInstanceData(hPrevInstance, (BYTE*) &SetUpData, sizeof(SETUPDATA));
|
|
|
|
return(FALSE); // We are not allowing multiple MsgWnd apps.
|
|
}
|
|
#endif
|
|
|
|
//*******************************************************************
|
|
|
|
//*******************************************************************
|
|
// InitMsgwnd - init the Msgwnd application
|
|
//
|
|
// paramaters:
|
|
// hInstance - The instance of this instance of this
|
|
// application.
|
|
// hPrevInstance - The instance of the previous instance
|
|
// of this application. This will be 0
|
|
// if this is the first instance.
|
|
// lpszCmdLine - A long pointer to the command line that
|
|
// started this application.
|
|
// cmdShow - Indicates how the window is to be shown
|
|
// initially. ie. SW_SHOWNORMAL, SW_HIDE,
|
|
// SW_MIMIMIZE.
|
|
//
|
|
// returns:
|
|
// TRUE if successful.
|
|
// or
|
|
// FALSE if failure.
|
|
//
|
|
//*******************************************************************
|
|
# pragma argsused
|
|
BOOL InitMsgwnd(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|
LPSTR lpszCmdLine, int cmdShow)
|
|
{
|
|
BOOL brc;
|
|
|
|
#if defined(__WIN32__)
|
|
brc = InitMsgwndFirst(hInstance);
|
|
#else
|
|
if (! hPrevInstance)
|
|
brc = InitMsgwndFirst(hInstance);
|
|
else
|
|
brc = InitMsgwndAdded(hPrevInstance);
|
|
#endif
|
|
|
|
if (brc == TRUE)
|
|
brc = InitMsgwndEvery(hInstance, cmdShow);
|
|
|
|
return(brc);
|
|
}
|
|
|
|
//*******************************************************************
|
|
// InitMsgwndFirst - done only for first instance of Msgwnd
|
|
//
|
|
// paramaters:
|
|
// hInstance - The instance of this instance of this
|
|
// application.
|
|
//
|
|
// returns:
|
|
// TRUE if successful.
|
|
// or
|
|
// FALSE if failure.
|
|
//
|
|
//*******************************************************************
|
|
BOOL InitMsgwndFirst(HINSTANCE hInstance)
|
|
{
|
|
WNDCLASS wcMsgwndClass;
|
|
|
|
LoadString(hInstance, IDS_NAME, (LPSTR) SetUpData.szAppName, 10);
|
|
|
|
// fill in window class information
|
|
|
|
wcMsgwndClass.lpszClassName = SetUpData.szAppName;
|
|
wcMsgwndClass.hInstance = hInstance;
|
|
wcMsgwndClass.lpfnWndProc = MsgwndWndProc;
|
|
wcMsgwndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wcMsgwndClass.hIcon = LoadIcon(hInstance, SetUpData.szAppName);
|
|
wcMsgwndClass.lpszMenuName = (LPSTR) SetUpData.szAppName;
|
|
wcMsgwndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
|
|
wcMsgwndClass.style = CS_HREDRAW | CS_VREDRAW;
|
|
wcMsgwndClass.cbClsExtra = 0;
|
|
wcMsgwndClass.cbWndExtra = 0;
|
|
|
|
// register the class
|
|
|
|
if (!RegisterClass(&wcMsgwndClass))
|
|
return(FALSE);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
//*******************************************************************
|
|
// InitMsgwndEvery - done for every instance of Msgwnd
|
|
//
|
|
// paramaters:
|
|
// hInstance - The instance of this instance of this
|
|
// application.
|
|
// cmdShow - Indicates how the window is to be shown
|
|
// initially. ie. SW_SHOWNORMAL, SW_HIDE,
|
|
// SW_MIMIMIZE.
|
|
//
|
|
// returns:
|
|
// TRUE if successful.
|
|
//
|
|
//*******************************************************************
|
|
BOOL InitMsgwndEvery(HINSTANCE hInstance, int cmdShow)
|
|
{
|
|
TEXTMETRIC tm;
|
|
HDC hDC;
|
|
char *cp;
|
|
char szWinLocStr[40];
|
|
int x, y, w, h;
|
|
|
|
hInst = hInstance; // save for use by window procs
|
|
|
|
// Get last location and size of Msgwnd from WIN.INI file.
|
|
GetProfileString("Msgwnd",
|
|
"Window",
|
|
"0,160,500,150",
|
|
szWinLocStr,
|
|
sizeof(szWinLocStr));
|
|
|
|
// Decode location and size of window from profile string.
|
|
cp = szWinLocStr;
|
|
x = (int) strtol(cp, &cp, 10);
|
|
cp++;
|
|
y = (int) strtol(cp, &cp, 10);
|
|
cp++;
|
|
w = (int) strtol(cp, &cp, 10);
|
|
cp++;
|
|
h = (int) strtol(cp, &cp, 10);
|
|
|
|
// Create our window.
|
|
hWndMain = CreateWindow(
|
|
SetUpData.szAppName, // window class name
|
|
SetUpData.szAppName, // window title
|
|
WS_OVERLAPPEDWINDOW | // type of window
|
|
WS_HSCROLL |
|
|
WS_VSCROLL,
|
|
x, // x window location
|
|
y, // y
|
|
w, // cx and size
|
|
h, // cy
|
|
NULL, // no parent for this window
|
|
NULL, // use the class menu
|
|
hInstance, // who created this window
|
|
NULL // no parms to pass on
|
|
);
|
|
|
|
// Get window display context.
|
|
hDC = GetDC(hWndMain);
|
|
|
|
// Build fixed screen font.
|
|
cursfont.lfHeight = 6;
|
|
cursfont.lfWidth = 6;
|
|
cursfont.lfEscapement = 0;
|
|
cursfont.lfOrientation = 0;
|
|
cursfont.lfWeight = FW_NORMAL;
|
|
cursfont.lfItalic = FALSE;
|
|
cursfont.lfUnderline = FALSE;
|
|
cursfont.lfStrikeOut = FALSE;
|
|
cursfont.lfCharSet = ANSI_CHARSET;
|
|
cursfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
|
|
cursfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
cursfont.lfQuality = DEFAULT_QUALITY;
|
|
cursfont.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
|
|
strcpy((char *)cursfont.lfFaceName, "System");
|
|
|
|
hnewsfont = CreateFontIndirect((LPLOGFONT) &cursfont);
|
|
|
|
// Install fixed font in display context so text metrics will reflect
|
|
// that font.
|
|
holdsfont = SelectObject(hDC, hnewsfont);
|
|
|
|
// Get text metrics to be used when painting the window.
|
|
GetTextMetrics(hDC, &tm);
|
|
xChar = tm.tmAveCharWidth;
|
|
yChar = tm.tmHeight + tm.tmExternalLeading;
|
|
yCharnl = tm.tmHeight;
|
|
|
|
// Init a blank line.
|
|
blanklen = 255;
|
|
memset(blanks, ' ', blanklen);
|
|
|
|
// Release the display context.
|
|
ReleaseDC(hWndMain, hDC);
|
|
|
|
ShowWindow(hWndMain, cmdShow);
|
|
UpdateWindow(hWndMain);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
//*******************************************************************
|
|
// CloseMsgwnd - done at termination of every instance of Msgwnd
|
|
//
|
|
// paramaters:
|
|
// hWnd - The callers window handle.
|
|
//
|
|
//*******************************************************************
|
|
void CloseMsgwnd(HWND hWnd)
|
|
{
|
|
RECT wrect;
|
|
char szWinLocStr[40];
|
|
int w, h;
|
|
|
|
// Clear out kept strings.
|
|
ClearKeep();
|
|
|
|
// Get location and size of our window on the screen so we can
|
|
// come back up in the same spot next time we are invoked.
|
|
|
|
GetWindowRect(hWnd, (LPRECT) &wrect);
|
|
w = wrect.right - wrect.left;
|
|
h = wrect.bottom - wrect.top;
|
|
|
|
// Make a string with our window location and size.
|
|
sprintf(szWinLocStr, "%d,%d,%d,%d", wrect.left, wrect.top, w, h);
|
|
|
|
// Save in WIN.INI file.
|
|
WriteProfileString("Msgwnd",
|
|
"Window",
|
|
szWinLocStr);
|
|
|
|
// Delete font
|
|
DeleteObject(hnewsfont);
|
|
}
|
|
|
|
//*******************************************************************
|
|
// About - handle about dialog messages
|
|
//
|
|
// paramaters:
|
|
// hDlg - The window handle for this dialog box
|
|
// message - The message number
|
|
// wParam - The WPARAM parameter for this message
|
|
// lParam - The LPARAM parameter for this message
|
|
//
|
|
// returns:
|
|
// Depends on message.
|
|
//
|
|
//*******************************************************************
|
|
# pragma argsused
|
|
BOOL CALLBACK _export About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (message == WM_INITDIALOG)
|
|
return(TRUE);
|
|
|
|
else if (message == WM_COMMAND)
|
|
{
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam))
|
|
{
|
|
case IDOK:
|
|
EndDialog(hDlg, TRUE);
|
|
return(TRUE);
|
|
|
|
default:
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
//*******************************************************************
|
|
|
|
//*******************************************************************
|
|
// MsgwndWndProc - every message for this instance will come here
|
|
//
|
|
// Handle the messages for this application.
|
|
//
|
|
// 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 MsgwndWndProc(HWND hWnd, UINT message,
|
|
WPARAM wParam, LPARAM lParam)
|
|
{
|
|
DLGPROC lpproc;
|
|
int i;
|
|
HWND hClientWnd;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_DDE_INITIATE:
|
|
// If this message is recieved, it is being sent by another
|
|
// applicaton that is looking for a server on a particular
|
|
// application/topic combination.
|
|
|
|
// Get the handle of this potential client.
|
|
hClientWnd = (HWND) wParam;
|
|
|
|
// Go see if we support the application and topic he wants.
|
|
DDEServerInit(hWnd, hClientWnd, lParam, "msgwnd", "screen");
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam))
|
|
{
|
|
case IDM_QUIT:
|
|
// User selected Quit on menu
|
|
PostMessage(hWnd, WM_CLOSE, 0, 0L);
|
|
break;
|
|
|
|
case IDM_HOME:
|
|
// Used to implement home to topleft from keyboard.
|
|
SendMessage(hWnd, WM_HSCROLL, GET_WM_HSCROLL_MPS (SB_TOP, 0, 0));
|
|
SendMessage(hWnd, WM_VSCROLL, GET_WM_VSCROLL_MPS (SB_TOP, 0, 0));
|
|
break;
|
|
|
|
case IDM_ABOUT:
|
|
// Display about box.
|
|
lpproc = (DLGPROC)MakeProcInstance((FARPROC)About, hInst);
|
|
DialogBox(hInst,
|
|
MAKEINTRESOURCE(ABOUT),
|
|
hWnd,
|
|
lpproc);
|
|
#pragma warn -eff
|
|
FreeProcInstance((FARPROC)lpproc);
|
|
#pragma warn .eff
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_SIZE:
|
|
// Save size of window client area.
|
|
yClient = HIWORD(lParam);
|
|
xClient = LOWORD(lParam);
|
|
|
|
// Go setup scroll ranges and file display area based upon
|
|
// client area size.
|
|
SetupScroll(hWnd);
|
|
break;
|
|
|
|
case WM_VSCROLL:
|
|
// React to the various vertical scroll related actions.
|
|
switch (GET_WM_VSCROLL_CODE(wParam, lParam))
|
|
{
|
|
case SB_TOP:
|
|
nVscrollInc = -nVscrollPos;
|
|
break;
|
|
|
|
case SB_BOTTOM:
|
|
nVscrollInc = nVscrollMax - nVscrollPos;
|
|
break;
|
|
|
|
case SB_LINEUP:
|
|
nVscrollInc = -1;
|
|
break;
|
|
|
|
case SB_LINEDOWN:
|
|
nVscrollInc = 1;
|
|
break;
|
|
|
|
case SB_PAGEUP:
|
|
nVscrollInc = -max(1, yClient / yChar);
|
|
break;
|
|
|
|
case SB_PAGEDOWN:
|
|
nVscrollInc = max(1, yClient / yChar);
|
|
break;
|
|
|
|
case SB_THUMBPOSITION:
|
|
nVscrollInc = GET_WM_VSCROLL_POS(wParam, lParam) - nVscrollPos;
|
|
break;
|
|
|
|
case SB_THUMBTRACK:
|
|
nVscrollInc = GET_WM_VSCROLL_POS(wParam, lParam) - nVscrollPos;
|
|
break;
|
|
|
|
default:
|
|
nVscrollInc = 0;
|
|
}
|
|
|
|
nVscrollInc = max(-nVscrollPos,
|
|
min(nVscrollInc, nVscrollMax - nVscrollPos));
|
|
if (nVscrollInc)
|
|
{
|
|
nVscrollPos += nVscrollInc;
|
|
ScrollWindow(hWnd, 0, -yChar * nVscrollInc, NULL, NULL);
|
|
SetScrollPos(hWnd, SB_VERT, nVscrollPos, TRUE);
|
|
UpdateWindow(hWnd);
|
|
}
|
|
break;
|
|
|
|
case WM_HSCROLL:
|
|
// React to the various horizontal scroll related actions.
|
|
switch (GET_WM_HSCROLL_CODE(wParam, lParam))
|
|
{
|
|
case SB_LINEUP:
|
|
nHscrollInc = -1;
|
|
break;
|
|
|
|
case SB_LINEDOWN:
|
|
nHscrollInc = 1;
|
|
break;
|
|
|
|
case SB_PAGEUP:
|
|
nHscrollInc = -8;
|
|
break;
|
|
|
|
case SB_PAGEDOWN:
|
|
nHscrollInc = 8;
|
|
break;
|
|
|
|
case SB_THUMBPOSITION:
|
|
nHscrollInc = GET_WM_HSCROLL_POS(wParam, lParam) - nHscrollPos;
|
|
break;
|
|
|
|
case SB_THUMBTRACK:
|
|
nHscrollInc = GET_WM_HSCROLL_POS(wParam, lParam) - nHscrollPos;
|
|
break;
|
|
|
|
default:
|
|
nHscrollInc = 0;
|
|
}
|
|
|
|
nHscrollInc = max(-nHscrollPos,
|
|
min(nHscrollInc, nHscrollMax - nHscrollPos));
|
|
if (nHscrollInc)
|
|
{
|
|
nHscrollPos += nHscrollInc;
|
|
ScrollWindow(hWnd, -xChar * nHscrollInc, 0, NULL, NULL);
|
|
SetScrollPos(hWnd, SB_HORZ, nHscrollPos, TRUE);
|
|
UpdateWindow(hWnd);
|
|
}
|
|
break;
|
|
|
|
case WM_KEYDOWN:
|
|
// Translate various keydown messages to appropriate horizontal
|
|
// and vertical scroll actions.
|
|
for (i = 0; i < NUMKEYS; i++)
|
|
{
|
|
if (wParam == key2scroll[i].wVirtkey)
|
|
{
|
|
SendMessage(hWnd, key2scroll[i].iMessage,
|
|
key2scroll[i].wRequest, 0L);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_PAINT:
|
|
// Go paint the client area of the window with the appropriate
|
|
// part of the selected file.
|
|
MsgwndPaint(hWnd);
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
// This is the end if we were closed by a DestroyWindow call.
|
|
CloseMsgwnd(hWnd); // take any necessary wrapup action.
|
|
PostQuitMessage(0); // this is the end...
|
|
break;
|
|
|
|
case WM_QUERYENDSESSION:
|
|
// If we return TRUE we are saying it's ok with us to end the
|
|
// windows session.
|
|
CloseMsgwnd(hWnd); // take any necessary wrapup action.
|
|
return((long) TRUE); // we agree to end session.
|
|
|
|
case WM_CLOSE:
|
|
// Tell windows to destroy our window.
|
|
DestroyWindow(hWnd);
|
|
break;
|
|
|
|
default:
|
|
// Let windows handle all messages we choose to ignore.
|
|
return(DefWindowProc(hWnd, message, wParam, lParam));
|
|
}
|
|
|
|
return(0L);
|
|
}
|
|
|
|
//*******************************************************************
|
|
// SetupScroll - setup scroll ranges
|
|
//
|
|
// Setup the vertical and horizontal scroll ranges and positions
|
|
// of the applicatons main window based on:
|
|
//
|
|
// numlines - The maximum number of lines to display.
|
|
// maxwidth - The maximum width of any line to display.
|
|
//
|
|
// The resulting variables, nVscrollPos and nPageMaxLines, are used
|
|
// by the function MsgwndPaint to determine what part of the selected
|
|
// file to display in the window.
|
|
//
|
|
// paramaters:
|
|
// hWnd - The callers window handle.
|
|
//
|
|
//*******************************************************************
|
|
void SetupScroll(HWND hWnd)
|
|
{
|
|
// numlines established during open
|
|
nVscrollMax = max(0, numlines - yClient / yChar);
|
|
nVscrollPos = min(nVscrollPos, nVscrollMax);
|
|
|
|
nHscrollMax = max(0, maxwidth - xClient / xChar);
|
|
nHscrollPos = min(nHscrollPos, nHscrollMax);
|
|
|
|
SetScrollRange (hWnd, SB_VERT, 0, nVscrollMax, FALSE);
|
|
SetScrollPos (hWnd, SB_VERT, nVscrollPos, TRUE);
|
|
|
|
SetScrollRange (hWnd, SB_HORZ, 0, nHscrollMax, FALSE);
|
|
SetScrollPos (hWnd, SB_HORZ, nHscrollPos, TRUE);
|
|
|
|
nPageMaxLines = min(numlines, yClient / yChar);
|
|
|
|
rect.left = 0;
|
|
rect.top = 0;
|
|
rect.right = xClient;
|
|
rect.bottom = yClient;
|
|
|
|
blanklen = rect.right / xChar + 1;
|
|
}
|
|
|
|
//*******************************************************************
|
|
// MsgwndPaint - paint the main window
|
|
//
|
|
// This function is responsible for redisplaying a portion of the saved
|
|
// strings. Which strings it displays depends on the current scroll
|
|
// position.
|
|
//
|
|
// paramaters:
|
|
// hWnd - The callers window handle
|
|
//
|
|
//*******************************************************************
|
|
void MsgwndPaint(HWND hWnd)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC hDC;
|
|
char currec[256];
|
|
int ypos;
|
|
LPSTR lcp;
|
|
int i;
|
|
int ndone;
|
|
|
|
// Get display context.
|
|
BeginPaint(hWnd, (LPPAINTSTRUCT) &ps);
|
|
hDC = ps.hdc;
|
|
|
|
// Select fixed font.
|
|
SelectObject(hDC, hnewsfont);
|
|
|
|
// Setup scroll ranges.
|
|
SetupScroll(hWnd);
|
|
|
|
// See if we have any lines to show.
|
|
if (hwm_keep)
|
|
{
|
|
// Y position of bottom line in client area.
|
|
ypos = rect.bottom - yChar;
|
|
|
|
// Index into keep list of first line (from bottom) to show.
|
|
i = nVscrollMax - nVscrollPos;
|
|
|
|
ndone = 1;
|
|
while (ndone)
|
|
{
|
|
lcp = GlobalLock(hkeep[i]);
|
|
if (lcp)
|
|
{
|
|
// We must fill line with blanks to width of window
|
|
// or else some previous longet text might show through.
|
|
_fstrcpy(currec, blanks);
|
|
|
|
// Line to show.
|
|
_fstrncpy(currec, lcp, _fstrlen(lcp));
|
|
|
|
// Send to window.
|
|
TextOut(hDC,
|
|
xChar * (-nHscrollPos + 0),
|
|
ypos,
|
|
currec,
|
|
blanklen);
|
|
|
|
// New Y is one character height higher.
|
|
ypos -= yChar;
|
|
|
|
GlobalUnlock(hkeep[i]);
|
|
}
|
|
|
|
// Index of next keep string to show.
|
|
i++;
|
|
|
|
// No use drawing lines beyond top of client area.
|
|
// They would not show, so don't wast the energy.
|
|
if (ypos < -yChar)
|
|
ndone = 0;
|
|
|
|
// Have we done all of the lines?
|
|
if (i > (hwm_keep - 1))
|
|
ndone = 0;
|
|
}
|
|
}
|
|
|
|
EndPaint(hWnd, (LPPAINTSTRUCT) &ps);
|
|
}
|
|
|
|
//*******************************************************************
|
|
// ScrollPrint - saves string sent to it and cause it to display
|
|
//
|
|
// This function gets a string and saves it in a list of strings.
|
|
// The oldest string is deleted when the list reaches its maximum
|
|
// size.
|
|
//
|
|
// Depending on the scroll position at the time the string is recieved
|
|
// one of two methods of displaying the string will be used:
|
|
//
|
|
// If the scroll position was at the bottom, the window is scrolled up
|
|
// one line, the bottom line is made invalid, and windows is told to
|
|
// repaint. This will cause only the new string to be output, resulting
|
|
// in minimum redraw on the screen.
|
|
//
|
|
// If the scroll position was not at the bottom of the window because
|
|
// the user had been looking at previous messages, windows will be told
|
|
// to redraw the entire window starting with the new string.
|
|
//
|
|
// paramaters:
|
|
// hWnd - The window to put the message in.
|
|
// str - the string to print in window.
|
|
//
|
|
//*******************************************************************
|
|
void ScrollPrint(HWND hWnd, char *str)
|
|
{
|
|
int i;
|
|
int lstr;
|
|
LPSTR lcp;
|
|
RECT trect;
|
|
|
|
// If our keep stack is full free oldest member.
|
|
if (hwm_keep >= MAX_KEEP)
|
|
GlobalFree(hkeep[hwm_keep]);
|
|
|
|
// Move all handles to make room for new one.
|
|
for (i = hwm_keep; i > 0; i--)
|
|
hkeep[i] = hkeep[i - 1];
|
|
|
|
// If keep stack not yet full add one to high watter mark.
|
|
if (hwm_keep < MAX_KEEP)
|
|
hwm_keep++;
|
|
|
|
// Make sure we know how many saved lines there are.
|
|
numlines = hwm_keep;
|
|
|
|
// Length of new string.
|
|
lstr = strlen(str);
|
|
|
|
// Is it longer than any previous string.
|
|
if (lstr > maxwidth)
|
|
maxwidth = lstr;
|
|
|
|
// Get storage to save it.
|
|
hkeep[0] = GlobalAlloc(GMEM_MOVEABLE, (DWORD) (lstr + 1));
|
|
if (hkeep[0])
|
|
{
|
|
// Lock it down to get address.
|
|
lcp = GlobalLock(hkeep[0]);
|
|
if (lcp)
|
|
{
|
|
// Save string.
|
|
_fstrcpy(lcp, str);
|
|
GlobalUnlock(hkeep[0]);
|
|
}
|
|
}
|
|
|
|
// See what we have to do to display it efficently.
|
|
if (!(nVscrollMax - nVscrollPos))
|
|
{
|
|
// We are scrolled to bottom of list.
|
|
|
|
// Scroll contents of window up one character hehght.
|
|
ScrollWindow(hWnd, 0, -yChar, &rect, &rect);
|
|
|
|
// Set scroll position to last line
|
|
nVscrollPos = numlines - yChar / yClient;
|
|
|
|
// Tell windows to repaint only the bottom line of window.
|
|
GetClientRect(hWnd, &trect);
|
|
trect.top = trect.bottom - yChar;
|
|
InvalidateRect(hWnd, &trect, TRUE);
|
|
}
|
|
else
|
|
{
|
|
// We are not scrolled to bottom of list.
|
|
|
|
// Set scroll position to last line.
|
|
nVscrollPos = numlines - yChar / yClient;
|
|
|
|
// Tell windows to repaint the entire window.
|
|
InvalidateRect(hWnd, NULL, TRUE);
|
|
}
|
|
}
|
|
|
|
//*******************************************************************
|
|
// ClearKeep - free all saved strings
|
|
//*******************************************************************
|
|
void ClearKeep()
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < hwm_keep; i++)
|
|
{
|
|
GlobalFree(hkeep[i]);
|
|
hkeep[i] = 0;
|
|
}
|
|
|
|
// Reset counters.
|
|
numlines = hwm_keep = 0;
|
|
}
|
|
|
|
//*******************************************************************
|
|
|
|
//*******************************************************************
|
|
// DDEExecuteCommand - execute a command send by client
|
|
//
|
|
// paramaters:
|
|
// lpCommand - command from client to be executed.
|
|
//
|
|
// commands supported:
|
|
//
|
|
// print - print a line in window.
|
|
// [print ("line to print")]
|
|
//
|
|
// clear - clear the window.
|
|
// [clear]
|
|
//
|
|
// returns:
|
|
// 1 - if command successful.
|
|
// 0 - if not successful.
|
|
//
|
|
//*******************************************************************
|
|
int DDEExecuteCommand(LPSTR lpCommand)
|
|
{
|
|
int nRc;
|
|
LPSTR lcp;
|
|
LPSTR lcp1;
|
|
LPSTR lcp2;
|
|
char buf[256];
|
|
|
|
// Init return code.
|
|
nRc = 0;
|
|
|
|
// Find start of command.
|
|
lcp = _fstrchr(lpCommand, '[');
|
|
if (lcp)
|
|
{
|
|
// See what the command is.
|
|
lcp++;
|
|
|
|
if (!_fstrncmp(lcp, "print", 5)) // Print a line to window.
|
|
{
|
|
// Find string between quotes (does not support embeded quotes)
|
|
lcp1 = _fstrchr(lcp, '\"');
|
|
if (lcp1)
|
|
{
|
|
lcp1++;
|
|
lcp2 = _fstrchr(lcp1, '\"');
|
|
if (lcp2)
|
|
{
|
|
*lcp2 = 0;
|
|
_fstrcpy(buf, lcp1);
|
|
|
|
// Print the string to window.
|
|
ScrollPrint(hWndMain, buf);
|
|
|
|
// Increment line count.
|
|
plines++;
|
|
|
|
nRc = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (!_fstrncmp(lcp, "clear", 5)) // Clear window.
|
|
{
|
|
// Delete saved strings.
|
|
ClearKeep();
|
|
|
|
// Clear the window.
|
|
InvalidateRect(hWndMain, NULL, TRUE);
|
|
UpdateWindow(hWndMain);
|
|
|
|
// Reset line count.
|
|
plines = 0;
|
|
|
|
nRc = 1;
|
|
}
|
|
}
|
|
|
|
return(nRc);
|
|
}
|
|
|
|
//*******************************************************************
|
|
// DDEData - get data requested by client
|
|
//
|
|
// paramaters:
|
|
// szItem - name of data item requested.
|
|
//
|
|
// items supported:
|
|
//
|
|
// lines - the number lines printed to window.
|
|
//
|
|
// returns:
|
|
// Size of data item.
|
|
// or
|
|
// Zero if no data item.
|
|
//
|
|
//*******************************************************************
|
|
int DDEData(char *szItem, HANDLE *hData)
|
|
{
|
|
int nRc;
|
|
int len;
|
|
char buf[30];
|
|
LPSTR lpData;
|
|
|
|
// Init return code.
|
|
nRc = 0;
|
|
|
|
// See what data item is being requested.
|
|
if (!stricmp(szItem, "lines"))
|
|
{
|
|
// Format response.
|
|
sprintf(buf, "Lines = %d", plines);
|
|
|
|
// Get length of response.
|
|
len = strlen(buf);
|
|
|
|
// Get memory for response.
|
|
*hData = GlobalAlloc(GMEM_MOVEABLE, (DWORD) (len + 1));
|
|
if (*hData)
|
|
{
|
|
lpData = GlobalLock(*hData);
|
|
if (lpData)
|
|
{
|
|
// Copy response to memory.
|
|
_fstrcpy(lpData, buf);
|
|
GlobalUnlock(*hData);
|
|
|
|
// Set return code to length of data returned.
|
|
nRc = len;
|
|
}
|
|
else
|
|
{
|
|
GlobalFree(*hData);
|
|
*hData = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(nRc);
|
|
}
|
|
|
|
//*******************************************************************
|