Category : C++ Source Code
Archive   : NETBMFC.ZIP
Filename : NETBIOS.CPP

 
Output of file : NETBIOS.CPP contained in archive : NETBMFC.ZIP
#include "stdafx.h"
#include "netbios.h"

IMPLEMENT_DYNAMIC(CName, CWnd)

BEGIN_MESSAGE_MAP(CName, CWnd)
ON_MESSAGE(WM_ADDNAME, OnAddName)
ON_MESSAGE(WM_DELETENAME, OnDeleteName)
ON_MESSAGE(WM_SENDDATAGRAM, OnSendDatagram)
ON_MESSAGE(WM_RECEIVEDATAGRAM, OnReceiveDatagram)
ON_MESSAGE(WM_SENDBROADCAST, OnSendBroadcast)
ON_MESSAGE(WM_RECEIVEBROADCAST, OnReceiveBroadcast)
ON_MESSAGE(WM_LISTEN, OnListen)
ON_MESSAGE(WM_CALL, OnCall)
ON_MESSAGE(WM_SEND, OnSend)
ON_MESSAGE(WM_RECEIVE, OnReceive)
ON_MESSAGE(WM_HANGUP, OnHangup)
END_MESSAGE_MAP()


LONG CName::OnListen(UINT wParam, LONG lParam)
{
return ((CSession*)((NetCommand*)lParam)->getObject())->OnListen(wParam, lParam);
}

LONG CName::OnCall(UINT wParam, LONG lParam)
{
return ((CSession*)((NetCommand*)lParam)->getObject())->OnCall(wParam, lParam);
}

LONG CName::OnReceive(UINT wParam, LONG lParam)
{
return ((CSession*)((NetCommand*)lParam)->getObject())->OnReceive(wParam, lParam);
}

LONG CName::OnSend(UINT wParam, LONG lParam)
{
return ((CSession*)((NetCommand*)lParam)->getObject())->OnSend(wParam, lParam);
}

LONG CName::OnHangup(UINT wParam, LONG lParam)
{
return ((CSession*)((NetCommand*)lParam)->getObject())->OnHangup(wParam, lParam);
}

static CObArray CmdList;

void _loadds interrupt far _cdecl NetCommand::PostHandler(unsigned _es, unsigned _ds,
unsigned _di, unsigned _si,
unsigned _bp, unsigned _sp,
unsigned _bx, unsigned _dx,
unsigned _cx, unsigned _ax,
unsigned _ip, unsigned _cs,
unsigned flags)
{
LPNCB lpNcb = (LPNCB) MAKELONG(_bx, _es);
int index = Find(lpNcb);
if (index == -1)
return;

PostMessage(((NetCommand*)CmdList[index])->msg.hwnd,
((NetCommand*)CmdList[index])->msg.message,
((NetCommand*)CmdList[index])->msg.wParam,
((NetCommand*)CmdList[index])->msg.lParam);

CmdList.RemoveAt(index);
}

NetCommand* NetCommand::Find(HWND hWnd, int Command)
{
for (int i = 0; i < CmdList.GetSize(); i++)
if (((NetCommand*)CmdList[i])->msg.hwnd == hWnd &&
((NetCommand*)CmdList[i])->ncb->cCommand == Command)
return (NetCommand*)CmdList[i];

return NULL;
}

int NetCommand::Find(LPNCB lpNCB)
{
for (int i = 0; i < CmdList.GetSize(); i++)
if (((NetCommand*)CmdList[i])->ncb == lpNCB)
return i;

return -1;
}

BOOL NetCommand::CancelAllForName(CName* pName)
{
for (int i = 0; i < CmdList.GetSize(); i++)
{
if (((NetCommand*)CmdList[i])->msg.hwnd == pName->m_hWnd)
((NetCommand*)CmdList[i])->Cancel();
}

return WinYield();
}

BOOL NetCommand::CancelAllForObject(CObject* pObject)
{
for (int i = 0; i < CmdList.GetSize(); i++)
{
if (((NetCommand*)CmdList[i])->object == pObject)
((NetCommand*)CmdList[i])->Cancel();
}

return WinYield();
}

LPNCB PASCAL CreateNCB(void)
{
HANDLE hNCB;
LPNCB lpNCB;
DWORD dwMem;

dwMem = GlobalDosAlloc(sizeof(NCB));

if (dwMem == NULL)
return NULL;

hNCB = (HANDLE) LOWORD(dwMem);
GlobalPageLock(hNCB);
lpNCB = (LPNCB) MAKELONG(0, hNCB);
_fmemset(lpNCB, 0, sizeof(NCB));
return lpNCB;
}

BOOL FAR PASCAL DestroyNCB(LPNCB lpNCB)
{
HANDLE hNCB = (HANDLE) HIWORD(lpNCB);

if (hNCB == NULL)
return FALSE;

GlobalPageUnlock(hNCB);
GlobalDosFree((UINT)hNCB);
return TRUE;
}

NetCommand::NetCommand()
: CObject()
{
ncb = CreateNCB();
}

NetCommand::NetCommand(BYTE aCommand, BYTE aAdapter)
: CObject()
{
ncb = CreateNCB();
ncb->cCommand = aCommand;
ncb->cAdapterNum = aAdapter;
}

NetCommand::NetCommand(LPNCB aNcb)
: CObject()
{
ncb = aNcb;
}

NetCommand::~NetCommand(void)
{
Cancel();
DestroyNCB(ncb);
}

UINT NetCommand::Cancel(void)
{
if (!isPending())
return 0;

NetCommand cmd(NETBIOS_CANCEL, getAdapter());
cmd.setBuffer((LPSTR)ncb);
UINT status = cmd.sendNetBIOS(TRUE);
return status;
}

UINT NetCommand::WaitForResponse()
{
while (isPending() && WinYield());
return getStatus();
}

BOOL NetCommand::WinYield()
{
MSG msg;

while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
PostQuitMessage(0);
return FALSE;
}

TranslateMessage(&msg);
DispatchMessage(&msg);

}

return TRUE;
}

extern "C" WORD FAR PASCAL NetBIOSCall(void);

int NetCommand::callNetBIOS(void)
{
WORD errCode;
LPNCB aNCB = ncb;
FARPROC proc = (FARPROC) NetBIOSCall;

_asm {
push ax
push bx
push es
les bx,aNCB
call proc
xor ah,ah
mov errCode,ax
pop es
pop bx
pop ax
}

return errCode;
}

int NetCommand::sendNetBIOS(BOOL Wait)
{
if (Wait)
ncb->cCommand &= ~NO_WAIT;
else
ncb->cCommand |= NO_WAIT;

ncb->fnPost = 0L;

CmdList.Add(this);
UINT status = callNetBIOS();
while (isPending() && WinYield());
int index = Find(ncb);
if (index != -1)
CmdList.RemoveAt(index);
return getStatus();
}

int NetCommand::postNetBIOS(void)
{
ncb->cCommand |= NO_WAIT;
ncb->fnPost = 0L;
return callNetBIOS();
}

int NetCommand::postNetBIOS(HWND hWnd, UINT message, WPARAM param)
{
WORD errCode;

msg.hwnd = hWnd;
msg.message = message;
msg.wParam = param;
msg.lParam = (LONG) this;

ncb->cCommand |= NO_WAIT;
ncb->fnPost = (FARPROC) (void far *) PostHandler;


int index = CmdList.Add(this);
errCode = callNetBIOS();

if (errCode)
CmdList.RemoveAt(index);

return errCode;
}

UINT CName::Accept(int aEnableDatagramReceipt, BOOL aEnableBroadcastReceipt)
{
EnableDatagramReceipt = aEnableDatagramReceipt;
EnableBroadcastReceipt = aEnableBroadcastReceipt;
UINT status;

NetCommand* cmd = NetCommand::Find(m_hWnd, NETBIOS_RECEIVE_DATAGRAM);
if (cmd)
{
switch (EnableDatagramReceipt)
{
case CName::acceptNoDatagrams:
status = cmd->Cancel();
break;

case CName::acceptDatagrams:
if (cmd->getNameNumber() == -1)
status = cmd->Cancel();

PostReceiveDatagram();
break;

case CName::acceptAnyDatagrams:
if (cmd->getNameNumber() != -1)
status = cmd->Cancel();

PostReceiveDatagram(TRUE);
break;
}
}
else
{
switch (EnableDatagramReceipt)
{
case CName::acceptDatagrams:
PostReceiveDatagram();
break;

case CName::acceptAnyDatagrams:
PostReceiveDatagram(TRUE);
break;
}
}

cmd = NetCommand::Find(m_hWnd, NETBIOS_RECEIVE_BROADCAST);
if (cmd)
{
if (!EnableBroadcastReceipt)
status = cmd->Cancel();
}
else
if (!EnableBroadcastReceipt)
status = PostReceiveBroadcast();

return status;
}

LONG CName::OnAddName(UINT wParam, LPARAM lParam)
{
NetCommand* pNetCommand = (NetCommand*) lParam;
if (!pNetCommand->getStatus())
{
Adapter = pNetCommand->getAdapter();
NameNumber = pNetCommand->getNameNumber();
OnRegisterComplete(Adapter, NameNumber);
Accept();
}
else
OnError(pNetCommand);

delete pNetCommand;
return 0;
}

LONG CName::OnDeleteName(UINT wParam, LPARAM lParam)
{
NetCommand* pNetCommand = (NetCommand*) lParam;
if (!pNetCommand->getStatus())
{
OnUnregisterComplete(Adapter);
Adapter = 0;
NameNumber = 0;
}
else
OnError(pNetCommand);

delete pNetCommand;
return 0;
}

LONG CName::OnSendDatagram(UINT wParam, LPARAM lParam)
{
NetCommand* pNetCommand = (NetCommand*) lParam;
if (!pNetCommand->getStatus())
OnSendDatagramComplete(pNetCommand->getCallName());
else
OnError(pNetCommand);

delete pNetCommand;
return 0;
}

LONG CName::OnReceiveDatagram(UINT wParam, LPARAM lParam)
{
NetCommand* pNetCommand = (NetCommand*) lParam;
if (!pNetCommand->getStatus())
{
OnReceiveDatagramComplete(pNetCommand->getCallName(), pNetCommand->getBuffer(), pNetCommand->getBufferLength());
PostReceiveDatagram(EnableDatagramReceipt == CName::acceptAnyDatagrams ? TRUE : FALSE);
}
else
OnError(pNetCommand);

delete [] pNetCommand->getBuffer();
delete pNetCommand;
return 0;
}

LONG CName::OnSendBroadcast(UINT wParam, LPARAM lParam)
{
NetCommand* pNetCommand = (NetCommand*) lParam;
if (!pNetCommand->getStatus())
OnSendBroadcastComplete();
else
OnError(pNetCommand);

delete pNetCommand;
return 0;
}

LONG CName::OnReceiveBroadcast(UINT wParam, LPARAM lParam)
{
NetCommand* pNetCommand = (NetCommand*) lParam;
if (!pNetCommand->getStatus())
{
OnReceiveBroadcastComplete(pNetCommand->getCallName(), pNetCommand->getBuffer(), pNetCommand->getBufferLength());

PostReceiveBroadcast();
}
else
OnError(pNetCommand);

delete [] pNetCommand->getBuffer();
delete pNetCommand;
return 0;
}

void CName::OnError(NetCommand* pNetCommand)
{
switch (pNetCommand->getStatus())
{
case NB_COMMAND_CANCELLED:
break;

default:
{
char buffer[128];
wsprintf(buffer, "NetBIOS error 0x%x",
pNetCommand->getStatus());

MessageBox(buffer, "NetBIOS Error");
break;
}
}
}

CName::CName() : CWnd()
{
Adapter = 0;
NameNumber = ILLEGAL_NAME_NUM;
}

CName::CName(const char* aName)
{
CName();
SetName(aName);
}

UINT CName::Register(int aAdapter, BOOL Wait)
{
if (!m_hWnd)
{
CString className = AfxRegisterWndClass(CS_HREDRAW);
if (!CreateEx(0, className, Name, WS_OVERLAPPEDWINDOW, 0, 0, 20, 20, NULL, 0))
return -1;
}

NetCommand* cmd = new NetCommand(NETBIOS_ADD_NAME, aAdapter);

cmd->setName(Name); // name to add to adapter
cmd->setObject(this);

UINT status;
if (Wait)
{
status = cmd->sendNetBIOS();
if (!status)
{
Adapter = cmd->getAdapter();
NameNumber = cmd->getNameNumber();
Accept();
}
delete cmd;
return status;
}

status = cmd->postNetBIOS(m_hWnd, WM_ADDNAME); // call netbios

if (status)
delete cmd;

return status;
}

UINT CName::SendDatagramTo(LPCSTR aName, LPCSTR aMessage, UINT MessageLength, BOOL Wait)
{
NetCommand* cmd = new NetCommand(NETBIOS_SEND_DATAGRAM, Adapter);

cmd->setNameNumber(NameNumber);
cmd->setCallName((LPSTR)aName);
cmd->setBuffer((LPSTR)aMessage);
cmd->setBufferLength(MessageLength);
cmd->setObject(this);

UINT status;
if (Wait)
{
status = cmd->sendNetBIOS();
delete cmd;
return status;
}

status = cmd->postNetBIOS(m_hWnd, WM_SENDDATAGRAM); // call netbios

if (status)
delete cmd;

return status;
}

UINT CName::Broadcast(LPCSTR aMessage, UINT MessageLength, BOOL Wait)
{
NetCommand* cmd = new NetCommand(NETBIOS_SEND_BROADCAST, Adapter);

cmd->setNameNumber(NameNumber);
cmd->setBuffer((LPSTR)aMessage);
cmd->setBufferLength(MessageLength);
cmd->setObject(this);

UINT status;
if (Wait)
{
status = cmd->sendNetBIOS();
delete cmd;
return status;
}

status = cmd->postNetBIOS(m_hWnd, WM_SENDBROADCAST); // call netbios

if (status)
delete cmd;

return status;
}

UINT CName::Unregister(BOOL Wait)
{
NetCommand::CancelAllForName(this);

NetCommand* cmd = new NetCommand(NETBIOS_DELETE_NAME, Adapter);

cmd->setName(Name);
cmd->setObject(this);

UINT status;
if (Wait)
{
status = cmd->sendNetBIOS();
if (!status)
{
Adapter = 0;
NameNumber = 0;
}
delete cmd;
return status;
}

status = cmd->postNetBIOS(m_hWnd, WM_DELETENAME); // call netbios

if (status)
delete cmd;

return status;
}

CName::~CName()
{
for (int index = 0; index < SessionList.GetSize(); index++)
((CSession*)SessionList[index])->Hangup(TRUE);

Unregister(TRUE);
}

int CName::FindSession(CSession* aSession)
{
for (int index = 0; index < SessionList.GetSize(); index++)
if (((CSession*)SessionList[index])->GetSessionNumber() == aSession->GetSessionNumber())
return index;

return -1;
}

UINT CName::PostReceiveDatagram(BOOL ReceiveAny)
{
// construct NetBIOS DELETENAME command
NetCommand* cmd = new NetCommand(NETBIOS_RECEIVE_DATAGRAM, Adapter);

cmd->setNameNumber(ReceiveAny ? -1 : NameNumber);
cmd->setBufferLength(512);
cmd->setBuffer(new _far char[cmd->getBufferLength()]);
cmd->setObject(this);

UINT status = cmd->postNetBIOS(m_hWnd, WM_RECEIVEDATAGRAM); // call netbios
if (status)
delete [] cmd->getBuffer();

return status;
}

UINT CName::PostReceiveBroadcast()
{
// construct NetBIOS DELETENAME command
NetCommand* cmd = new NetCommand(NETBIOS_RECEIVE_BROADCAST, Adapter);

cmd->setNameNumber(NameNumber);
cmd->setBufferLength(512);
cmd->setBuffer(new _far char[cmd->getBufferLength()]);
cmd->setObject(this);

UINT status = cmd->postNetBIOS(m_hWnd, WM_RECEIVEBROADCAST); // call netbios
if (status)
delete [] cmd->getBuffer();

return status;
}

UINT CGroupName::Register(int aAdapter, BOOL Wait, BOOL aRecieveAny)
{
if (!m_hWnd)
{
CString className = AfxRegisterWndClass(CS_HREDRAW);
if (!CreateEx(0, className, Name, WS_OVERLAPPEDWINDOW, 0, 0, 20, 20, NULL, 0))
return -1;
}

NetCommand* cmd = new NetCommand(NETBIOS_ADD_GROUP_NAME, aAdapter);

cmd->setName(Name); // name to add to adapter
cmd->setObject(this);

UINT status;
if (Wait)
{
status = cmd->sendNetBIOS();
if (!status)
{
Adapter = cmd->getAdapter();
NameNumber = cmd->getNameNumber();
Accept();
}
delete cmd;
return status;
}

status = cmd->postNetBIOS(m_hWnd, WM_ADDNAME); // call netbios

if (status)
delete cmd;

return status;
}

// Session

CSession::CSession(CName* aName, UINT aReceiveBufferSize)
: CObject()
{
Name = aName;
SessionNumber = ILLEGAL_LSN;
ReceiveBufferSize = aReceiveBufferSize;
}

UINT CSession::Listen(LPCSTR aName, int SendTimeout, int ReceiveTimeout, BOOL Wait)
{
if (IsActive())
return 0;

NetCommand* cmd = new NetCommand(NETBIOS_LISTEN, Name->Adapter);

cmd->setName(Name->Name);
cmd->setCallName((LPSTR)aName);
cmd->setSendTimeout(SendTimeout);
cmd->setReceiveTimeout(ReceiveTimeout);
cmd->setObject(this);

UINT status;
if (Wait)
{
status = cmd->sendNetBIOS();
if (!status)
{
SessionNumber = cmd->getLSN();
Name->SessionList.Add(this);
PostReceive();
}

delete cmd;
return status;
}

status = cmd->postNetBIOS(Name->m_hWnd, WM_LISTEN); // call netbios

if (status)
delete cmd;

return status;
}

LONG CSession::OnListen(UINT wParam, LPARAM lParam)
{
NetCommand* pNetCommand = (NetCommand*) lParam;
if (!pNetCommand->getStatus())
{
SessionNumber = pNetCommand->getLSN();
Name->SessionList.Add(this);
if (ReceiveBufferSize)
PostReceive();
OnListenComplete(pNetCommand->getCallName(), SessionNumber);
}
else
OnError(pNetCommand);

delete pNetCommand;
return 0;
}

UINT CSession::Call(LPCSTR aName, int SendTimeout, int ReceiveTimeout, BOOL Wait)
{
if (IsActive())
return 0;

NetCommand* cmd = new NetCommand(NETBIOS_CALL, Name->Adapter);

cmd->setName(Name->Name);
cmd->setCallName((LPSTR)aName);
cmd->setSendTimeout(SendTimeout);
cmd->setReceiveTimeout(ReceiveTimeout);
cmd->setObject(this);

UINT status;
if (Wait)
{
status = cmd->sendNetBIOS();
if (!status)
{
SessionNumber = cmd->getLSN();
Name->SessionList.Add(this);
if (ReceiveBufferSize)
PostReceive();
}

delete cmd;
return status;
}

status = cmd->postNetBIOS(Name->m_hWnd, WM_CALL); // call netbios

if (status)
delete cmd;

return status;
}

LONG CSession::OnCall(UINT wParam, LPARAM lParam)
{
NetCommand* pNetCommand = (NetCommand*) lParam;
if (!pNetCommand->getStatus())
{
SessionNumber = pNetCommand->getLSN();
Name->SessionList.Add(this);
PostReceive();
OnCallComplete(pNetCommand->getCallName(), SessionNumber);
}
else
OnError(pNetCommand);

delete pNetCommand;
return 0;
}

UINT CSession::Hangup(BOOL Wait)
{
if (!IsActive())
return 0;

NetCommand* cmd = new NetCommand(NETBIOS_HANGUP, Name->Adapter);

cmd->setLSN(GetSessionNumber());
cmd->setObject(this);

UINT status;
if (Wait)
{
status = cmd->sendNetBIOS();
if (!status)
{
SessionNumber = ILLEGAL_LSN;
int index = Name->FindSession(this);
if (index != -1)
Name->SessionList.RemoveAt(index);
}

delete cmd;
return status;
}

status = cmd->postNetBIOS(Name->m_hWnd, WM_HANGUP); // call netbios

if (status)
delete cmd;

return status;
}

LONG CSession::OnHangup(UINT wParam, LPARAM lParam)
{
NetCommand* pNetCommand = (NetCommand*) lParam;
if (!pNetCommand->getStatus())
{
int index = Name->FindSession(this);
if (index != -1)
Name->SessionList.RemoveAt(index);
OnHangupComplete();
SessionNumber = ILLEGAL_LSN;
}
else
OnError(pNetCommand);

delete pNetCommand;
delete this;
return 0;
}

void CSession::OnError(NetCommand* pNetCommand)
{
switch (pNetCommand->getStatus())
{
case NB_COMMAND_CANCELLED:
case NB_SESSION_CLOSED:
break;

default:
{
char buffer[128];
wsprintf(buffer, "NetBIOS error 0x%x",
pNetCommand->getStatus());

::MessageBox(NULL, buffer, "NetBIOS Error", MB_OK);
break;
}
}
}

UINT CSession::Send(LPCSTR aMessage, UINT MessageLength, BOOL Wait)
{
NetCommand* cmd = new NetCommand(NETBIOS_SEND, Name->Adapter);

cmd->setLSN(SessionNumber);
cmd->setBuffer((LPSTR)aMessage);
cmd->setBufferLength(MessageLength);
cmd->setObject(this);

UINT status;
if (Wait)
{
status = cmd->sendNetBIOS();
delete cmd;
return status;
}

status = cmd->postNetBIOS(Name->m_hWnd, WM_SEND); // call netbios

if (status)
delete cmd;

return status;
}

LONG CSession::OnSend(UINT wParam, LPARAM lParam)
{
NetCommand* pNetCommand = (NetCommand*) lParam;
if (!pNetCommand->getStatus())
OnSendComplete();
else
OnError(pNetCommand);

delete pNetCommand;
return 0;
}

UINT CSession::Receive(LPSTR aMessage, UINT MessageLength)
{
NetCommand* cmd = new NetCommand(NETBIOS_RECEIVE, Name->Adapter);

cmd->setLSN(SessionNumber);
cmd->setBuffer((LPSTR)aMessage);
cmd->setBufferLength(MessageLength);
cmd->setObject(this);

UINT status = cmd->sendNetBIOS();
delete cmd;
return status;
}

LONG CSession::OnReceive(UINT wParam, LPARAM lParam)
{
NetCommand* pNetCommand = (NetCommand*) lParam;
if (pNetCommand->getStatus() == NB_MESSAGE_INCOMPLETE)
{
UINT BufferLength = pNetCommand->getBufferLength();
HANDLE hBuffer = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, BufferLength);
LPSTR lpBuffer = (LPSTR) GlobalLock(hBuffer);
_fmemcpy(lpBuffer, pNetCommand->getBuffer(), pNetCommand->getBufferLength());
delete [] pNetCommand->getBuffer();

while (pNetCommand->getStatus() == NB_MESSAGE_INCOMPLETE)
{
GlobalUnlock(hBuffer);
hBuffer = GlobalReAlloc(hBuffer, BufferLength + ReceiveBufferSize, GMEM_ZEROINIT);
lpBuffer = (LPSTR) GlobalLock(hBuffer);
pNetCommand->setBuffer(&lpBuffer[BufferLength]);
pNetCommand->sendNetBIOS();
BufferLength += pNetCommand->getBufferLength();
}

if (!pNetCommand->getStatus())
{
OnReceiveComplete(lpBuffer, BufferLength);
PostReceive();
}
else
OnError(pNetCommand);

GlobalUnlock(hBuffer);
GlobalFree(hBuffer);
delete pNetCommand;

return 0;
}

if (!pNetCommand->getStatus())
{
OnReceiveComplete(pNetCommand->getBuffer(), pNetCommand->getBufferLength());
PostReceive();
}
else
OnError(pNetCommand);

delete [] pNetCommand->getBuffer();
delete pNetCommand;
return 0;
}

UINT CSession::PostReceive()
{
NetCommand* cmd = new NetCommand(NETBIOS_RECEIVE, Name->Adapter);

cmd->setLSN(SessionNumber);
cmd->setBufferLength(ReceiveBufferSize);
cmd->setBuffer(new _far char[cmd->getBufferLength()]);
cmd->setObject(this);

UINT status = cmd->postNetBIOS(Name->m_hWnd, WM_RECEIVE); // call netbios
if (status)
delete [] cmd->getBuffer();

return status;
}


  3 Responses to “Category : C++ Source Code
Archive   : NETBMFC.ZIP
Filename : NETBIOS.CPP

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/