mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
890 lines
26 KiB
890 lines
26 KiB
//THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
//ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
//THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright 1993-1996 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// MODULE: terminal.c
|
|
//
|
|
// PURPOSE: Terminal screen simulation
|
|
//
|
|
// FUNCTIONS:
|
|
// CreateTerminalDlg()
|
|
// TerminalDlgWndProc()
|
|
// TerminalScreenWndProc()
|
|
// OnCommand()
|
|
// GetInput()
|
|
// SendCharacter()
|
|
// AdjustTerminal()
|
|
// TerminalThread()
|
|
//
|
|
|
|
#include "unimdm.h" // includes common header files and global declarations
|
|
#include "umdmspi.h" // includes common header files and global declarations
|
|
#include "wndthrd.h" // includes UI declarations
|
|
#include "rcids.h" // includes the resource definitions
|
|
|
|
//****************************************************************************
|
|
// Constants Declaration
|
|
//****************************************************************************
|
|
|
|
#define MAXTITLE 32
|
|
#define MAXMESSAGE 256
|
|
|
|
#define WM_MODEMNOTIFY (WM_USER + 998)
|
|
#define WM_EOLFROMDEVICE (WM_USER + 999)
|
|
|
|
#define SIZE_ReceiveBuf 1024
|
|
#define SIZE_SendBuf 1
|
|
|
|
#define Y_MARGIN 4
|
|
#define X_SPACING 2
|
|
#define MIN_X 170
|
|
#define MIN_Y 80
|
|
|
|
#define TERMINAL_BK_COLOR (RGB( 0, 0, 0 ))
|
|
#define TERMINAL_FR_COLOR (RGB( 255, 255, 255 ))
|
|
#define MAXTERMLINE 24
|
|
|
|
#define READ_EVENT 0
|
|
#define STOP_EVENT 1
|
|
#define MAX_EVENT 2
|
|
|
|
//****************************************************************************
|
|
// Type Definitions
|
|
//****************************************************************************
|
|
|
|
typedef struct tagTERMDLG {
|
|
HANDLE hport;
|
|
HANDLE hThread;
|
|
HANDLE hEvent[MAX_EVENT];
|
|
HWND hwnd;
|
|
PBYTE pbyteReceiveBuf;
|
|
PBYTE pbyteSendBuf;
|
|
HBRUSH hbrushScreenBackground;
|
|
HFONT hfontTerminal;
|
|
WNDPROC WndprocOldTerminalScreen;
|
|
DWORD idLine;
|
|
HWND ParenthWnd;
|
|
} TERMDLG, *PTERMDLG, FAR* LPTERMDLG;
|
|
|
|
//****************************************************************************
|
|
// Function prototypes
|
|
//****************************************************************************
|
|
|
|
LRESULT FAR PASCAL TerminalDlgWndProc(HWND hwnd,
|
|
UINT wMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam );
|
|
LRESULT FAR PASCAL TerminalScreenWndProc(HWND hwnd,
|
|
UINT wMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam );
|
|
BOOL NEAR PASCAL OnCommand (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
BOOL NEAR PASCAL GetInput (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
VOID NEAR PASCAL SendCharacter( HWND hwnd, BYTE byte );
|
|
VOID NEAR PASCAL AdjustTerminal (HWND hwnd, int wWidth, int wHeight);
|
|
void WINAPI TerminalThread (PTERMDLG pTerminaldialog);
|
|
|
|
//****************************************************************************
|
|
// HWND CreateTerminalDlg(HWND hwndOwner, DWORD idLine)
|
|
//
|
|
// Function: creates a modeless terminal dialog box
|
|
//
|
|
// Returns: the modeless window handle
|
|
//
|
|
//****************************************************************************
|
|
|
|
HWND CreateTerminalDlg(HWND hwndOwner, DWORD idLine)
|
|
{
|
|
HANDLE hComm;
|
|
HWND hwnd;
|
|
COMMTIMEOUTS commtimeout;
|
|
PTERMDLG pTerminaldialog;
|
|
DWORD id;
|
|
int i;
|
|
int iRet;
|
|
TERMREQ TermReq;
|
|
|
|
TUISPIDLLCALLBACK Callback;
|
|
|
|
Callback=GetCallbackProc(hwndOwner);
|
|
|
|
// Get the terminal parameters
|
|
//
|
|
TermReq.DlgReq.dwCmd = UI_REQ_TERMINAL_INFO;
|
|
TermReq.DlgReq.dwParam = GetCurrentProcessId();
|
|
|
|
(*Callback)(idLine, TUISPIDLL_OBJECT_LINEID,
|
|
(LPVOID)&TermReq, sizeof(TermReq));
|
|
hComm = TermReq.hDevice;
|
|
|
|
// Allocate the terminal buffer
|
|
//
|
|
if ((pTerminaldialog = (PTERMDLG)LocalAlloc(LPTR, sizeof(*pTerminaldialog)))
|
|
== NULL)
|
|
return NULL;
|
|
|
|
if ((pTerminaldialog->pbyteReceiveBuf = (PBYTE)LocalAlloc(LMEM_FIXED,
|
|
SIZE_ReceiveBuf
|
|
+ SIZE_SendBuf))
|
|
== NULL)
|
|
{
|
|
LocalFree((HLOCAL)pTerminaldialog);
|
|
return NULL;
|
|
};
|
|
pTerminaldialog->pbyteSendBuf = pTerminaldialog->pbyteReceiveBuf + SIZE_ReceiveBuf;
|
|
|
|
// Initialize the terminal buffer
|
|
//
|
|
pTerminaldialog->ParenthWnd= hwndOwner;
|
|
pTerminaldialog->hport = hComm;
|
|
pTerminaldialog->idLine = idLine;
|
|
pTerminaldialog->hbrushScreenBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
|
|
pTerminaldialog->hfontTerminal = (HFONT)GetStockObject( SYSTEM_FIXED_FONT );
|
|
|
|
// Start receiving from the port
|
|
//
|
|
commtimeout.ReadIntervalTimeout = MAXDWORD;
|
|
commtimeout.ReadTotalTimeoutMultiplier = 0;
|
|
commtimeout.ReadTotalTimeoutConstant = 0;
|
|
commtimeout.WriteTotalTimeoutMultiplier= 0;
|
|
commtimeout.WriteTotalTimeoutConstant = 1000;
|
|
SetCommTimeouts(hComm, &commtimeout);
|
|
|
|
SetCommMask(hComm, EV_RXCHAR);
|
|
|
|
if (TermReq.dwTermType == TERMINAL_PRE) {
|
|
|
|
#define ECHO_OFF "ATE1\r"
|
|
|
|
COMMTIMEOUTS commtimeout;
|
|
HANDLE hEvent;
|
|
|
|
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
|
|
if (hEvent != NULL) {
|
|
|
|
DWORD cb;
|
|
OVERLAPPED ov;
|
|
BOOLEAN bResult;
|
|
|
|
ov.Offset = 0;
|
|
ov.OffsetHigh = 0;
|
|
|
|
// OR with 1 to prevent it from being posted to the completion port.
|
|
//
|
|
ov.hEvent = (HANDLE)((DWORD)hEvent | 1);
|
|
|
|
bResult=WriteFile(
|
|
hComm,
|
|
ECHO_OFF,
|
|
sizeof(ECHO_OFF)-1,
|
|
&cb,
|
|
&ov
|
|
);
|
|
|
|
|
|
if (!bResult) {
|
|
|
|
DWORD dwResult = GetLastError();
|
|
|
|
if (ERROR_IO_PENDING == dwResult) {
|
|
|
|
GetOverlappedResult(
|
|
hComm,
|
|
&ov,
|
|
&cb,
|
|
TRUE
|
|
);
|
|
}
|
|
}
|
|
|
|
CloseHandle(hEvent);
|
|
}
|
|
}
|
|
|
|
|
|
// Create read thread and the synchronization objects
|
|
for (i = 0; i < MAX_EVENT; i++)
|
|
{
|
|
pTerminaldialog->hEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
};
|
|
|
|
pTerminaldialog->hThread = CreateThread(NULL, 0,
|
|
(LPTHREAD_START_ROUTINE) TerminalThread,
|
|
pTerminaldialog, 0, &id);
|
|
|
|
// Create the terminal window
|
|
hwnd = CreateDialogParam(ghInstance,
|
|
MAKEINTRESOURCE(IDD_TERMINALDLG),
|
|
hwndOwner,
|
|
(DLGPROC)TerminalDlgWndProc,
|
|
(LPARAM)pTerminaldialog);
|
|
|
|
if (IsWindow(hwnd))
|
|
{
|
|
TCHAR szTitle[MAXTITLE];
|
|
|
|
// Set window caption
|
|
//
|
|
LoadString (ghInstance,
|
|
(TermReq.dwTermType == TERMINAL_POST)?
|
|
IDS_POSTTERM_TITLE : IDS_PRETERM_TITLE,
|
|
szTitle, sizeof(szTitle));
|
|
SetWindowText(hwnd, szTitle);
|
|
}
|
|
else
|
|
{
|
|
// The terminal dialog was terminalted, free resources
|
|
//
|
|
SetEvent(pTerminaldialog->hEvent[STOP_EVENT]);
|
|
|
|
SetCommMask(hComm, 0);
|
|
WaitForSingleObject(pTerminaldialog->hThread, INFINITE);
|
|
CloseHandle(pTerminaldialog->hThread);
|
|
|
|
for (i = 0; i < MAX_EVENT; i++)
|
|
{
|
|
CloseHandle(pTerminaldialog->hEvent[i]);
|
|
};
|
|
|
|
LocalFree((HLOCAL)pTerminaldialog->pbyteReceiveBuf);
|
|
LocalFree((HLOCAL)pTerminaldialog);
|
|
|
|
hwnd = NULL;
|
|
};
|
|
|
|
return hwnd;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** Terminal Window Procedure
|
|
**----------------------------------------------------------------------------
|
|
*/
|
|
|
|
LRESULT FAR PASCAL TerminalDlgWndProc(HWND hwnd,
|
|
UINT wMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam )
|
|
{
|
|
PTERMDLG pTerminaldialog;
|
|
HWND hwndScrn;
|
|
RECT rect;
|
|
|
|
switch (wMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
pTerminaldialog = (PTERMDLG)lParam;
|
|
SetWindowLong(hwnd, DWL_USER, (LONG)lParam);
|
|
SetForegroundWindow(hwnd);
|
|
pTerminaldialog->hwnd = hwnd;
|
|
|
|
// Install subclassed WndProcs.
|
|
//
|
|
hwndScrn = GetDlgItem(hwnd, CID_T_EB_SCREEN);
|
|
pTerminaldialog->WndprocOldTerminalScreen =
|
|
(WNDPROC)SetWindowLong( hwndScrn, GWL_WNDPROC,
|
|
(LONG)TerminalScreenWndProc );
|
|
|
|
// Set the terminal screen font
|
|
//
|
|
SendMessage(hwndScrn, WM_SETFONT, (WPARAM)pTerminaldialog->hfontTerminal,
|
|
0L);
|
|
|
|
// Adjust the dimension
|
|
//
|
|
GetClientRect(hwnd, &rect);
|
|
AdjustTerminal(hwnd, rect.right-rect.left, rect.bottom-rect.top);
|
|
|
|
// Start receiving from the port
|
|
//
|
|
PostMessage(hwnd, WM_MODEMNOTIFY, 0, 0);
|
|
|
|
// Set the input focus to the screen
|
|
//
|
|
SetFocus(hwndScrn);
|
|
return 0;
|
|
|
|
case WM_CTLCOLOREDIT:
|
|
{
|
|
pTerminaldialog = (PTERMDLG)GetWindowLong(hwnd, DWL_USER);
|
|
|
|
/* Set terminal screen colors to TTY-ish green on black.
|
|
*/
|
|
if (pTerminaldialog->hbrushScreenBackground)
|
|
{
|
|
SetBkColor( (HDC)wParam, TERMINAL_BK_COLOR );
|
|
SetTextColor((HDC)wParam, TERMINAL_FR_COLOR );
|
|
|
|
return (LRESULT)pTerminaldialog->hbrushScreenBackground;
|
|
}
|
|
|
|
break;
|
|
};
|
|
|
|
case WM_MODEMNOTIFY:
|
|
return GetInput(hwnd, wMsg, wParam, lParam);
|
|
|
|
case WM_COMMAND:
|
|
|
|
// Handle the control activities
|
|
//
|
|
return OnCommand(hwnd, wMsg, wParam, lParam);
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
DLGREQ DlgReq;
|
|
int i;
|
|
TUISPIDLLCALLBACK Callback;
|
|
|
|
pTerminaldialog = (PTERMDLG)GetWindowLong(hwnd, DWL_USER);
|
|
SetWindowLong( GetDlgItem(hwnd, CID_T_EB_SCREEN), GWL_WNDPROC,
|
|
(LONG)pTerminaldialog->WndprocOldTerminalScreen );
|
|
|
|
// Destroy the dialog
|
|
//
|
|
DlgReq.dwCmd = UI_REQ_END_DLG;
|
|
DlgReq.dwParam = TERMINAL_DLG;
|
|
|
|
Callback=GetCallbackProc(pTerminaldialog->ParenthWnd);
|
|
|
|
(*Callback)(pTerminaldialog->idLine, TUISPIDLL_OBJECT_LINEID,
|
|
(LPVOID)&DlgReq, sizeof(DlgReq));
|
|
|
|
// The terminal dialog was terminated, free resources
|
|
//
|
|
SetEvent(pTerminaldialog->hEvent[STOP_EVENT]);
|
|
|
|
if (pTerminaldialog->hport != NULL)
|
|
{
|
|
SetCommMask(pTerminaldialog->hport, 0);
|
|
};
|
|
|
|
if (pTerminaldialog->hThread != NULL)
|
|
{
|
|
WaitForSingleObject(pTerminaldialog->hThread, INFINITE);
|
|
CloseHandle(pTerminaldialog->hThread);
|
|
};
|
|
CloseHandle(pTerminaldialog->hport);
|
|
|
|
for (i = 0; i < MAX_EVENT; i++)
|
|
{
|
|
CloseHandle(pTerminaldialog->hEvent[i]);
|
|
};
|
|
|
|
LocalFree((HLOCAL)pTerminaldialog->pbyteReceiveBuf);
|
|
LocalFree((HLOCAL)pTerminaldialog);
|
|
break;
|
|
}
|
|
case WM_SIZE:
|
|
AdjustTerminal(hwnd, (int)LOWORD(lParam), (int)HIWORD(lParam));
|
|
break;
|
|
|
|
case WM_GETMINMAXINFO:
|
|
{
|
|
MINMAXINFO FAR* lpMinMaxInfo = (MINMAXINFO FAR*)lParam;
|
|
DWORD dwUnit = GetDialogBaseUnits();
|
|
|
|
lpMinMaxInfo->ptMinTrackSize.x = (MIN_X*LOWORD(dwUnit))/4;
|
|
lpMinMaxInfo->ptMinTrackSize.y = (MIN_Y*LOWORD(dwUnit))/4;
|
|
break;
|
|
};
|
|
};
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** Terminal Screen Subclasses Window Procedure
|
|
**----------------------------------------------------------------------------
|
|
*/
|
|
|
|
LRESULT FAR PASCAL TerminalScreenWndProc(HWND hwnd,
|
|
UINT wMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam )
|
|
{
|
|
HWND hwndParent;
|
|
PTERMDLG pTerminaldialog;
|
|
|
|
hwndParent = GetParent(hwnd);
|
|
pTerminaldialog = (PTERMDLG)GetWindowLong(hwndParent, DWL_USER);
|
|
|
|
if (wMsg == WM_EOLFROMDEVICE)
|
|
{
|
|
/* Remove the first line if the next line exceeds the maximum line
|
|
*/
|
|
if (SendMessage(hwnd, EM_GETLINECOUNT, 0, 0L) == MAXTERMLINE)
|
|
{
|
|
SendMessage(hwnd, EM_SETSEL, 0,
|
|
SendMessage(hwnd, EM_LINEINDEX, 1, 0L));
|
|
SendMessage(hwnd, EM_REPLACESEL, 0, (LPARAM)(LPTSTR)TEXT(""));
|
|
SendMessage(hwnd, EM_SETSEL, 32767, 32767);
|
|
SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
|
|
};
|
|
|
|
/* An end-of-line in the device input was received. Send a linefeed
|
|
** character to the window.
|
|
*/
|
|
wParam = '\n';
|
|
wMsg = WM_CHAR;
|
|
}
|
|
else
|
|
{
|
|
BOOL fCtrlKeyDown = (GetKeyState( VK_CONTROL ) < 0);
|
|
BOOL fShiftKeyDown = (GetKeyState( VK_SHIFT ) < 0);
|
|
|
|
if (wMsg == WM_KEYDOWN)
|
|
{
|
|
/* The key was pressed by the user.
|
|
*/
|
|
if (wParam == VK_RETURN && !fCtrlKeyDown && !fShiftKeyDown)
|
|
{
|
|
/* Enter key pressed without Shift or Ctrl is discarded. This
|
|
** prevents Enter from being interpreted as "press default
|
|
** button" when pressed in the edit box.
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
if (fCtrlKeyDown && wParam == VK_TAB)
|
|
{
|
|
/* Ctrl+Tab pressed. Send a tab character to the device.
|
|
** Pass tab thru to let the edit box handle the visuals.
|
|
** Ctrl+Tab doesn't generate a WM_CHAR.
|
|
*/
|
|
SendCharacter( hwndParent, (BYTE )VK_TAB );
|
|
}
|
|
|
|
if (GetKeyState( VK_MENU ) < 0)
|
|
{
|
|
return (CallWindowProc(pTerminaldialog->WndprocOldTerminalScreen, hwnd, wMsg, wParam, lParam ));
|
|
};
|
|
}
|
|
else if (wMsg == WM_CHAR)
|
|
{
|
|
/* The character was typed by the user.
|
|
*/
|
|
if (wParam == VK_TAB)
|
|
{
|
|
/* Ignore tabs...Windows sends this message when Tab (leave
|
|
** field) is pressed but not when Ctrl+Tab (insert a TAB
|
|
** character) is pressed...weird.
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
{
|
|
CHAR chAnsi;
|
|
|
|
if (WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
(LPWSTR)&wParam,
|
|
1,
|
|
&chAnsi,
|
|
1,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
SendCharacter( hwndParent, (BYTE )chAnsi );
|
|
}
|
|
}
|
|
#else // UNICODE
|
|
SendCharacter( hwndParent, (BYTE )wParam );
|
|
#endif // UNICODE
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Call the previous window procedure for everything else.
|
|
*/
|
|
return (CallWindowProc(pTerminaldialog->WndprocOldTerminalScreen, hwnd, wMsg, wParam, lParam ));
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** Terminal Window's Control Handler
|
|
**----------------------------------------------------------------------------
|
|
*/
|
|
|
|
BOOL NEAR PASCAL OnCommand (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam))
|
|
{
|
|
case CID_T_EB_SCREEN:
|
|
{
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case EN_SETFOCUS:
|
|
{
|
|
/* Turn off the default button whenever the terminal
|
|
** window has the focus. Pressing [Return] in the
|
|
** terminal acts like a normal terminal.
|
|
*/
|
|
SendDlgItemMessage(hwnd, CID_T_PB_ENTER, BM_SETSTYLE,
|
|
(WPARAM)BS_DEFPUSHBUTTON, TRUE);
|
|
|
|
/* Don't select the entire string on entry.
|
|
*/
|
|
SendDlgItemMessage(hwnd, CID_T_EB_SCREEN, EM_SETSEL,
|
|
32767, 32767);
|
|
SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
|
|
break;
|
|
};
|
|
};
|
|
|
|
break;
|
|
};
|
|
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
{
|
|
PTERMDLG pTerminaldialog;
|
|
|
|
pTerminaldialog = (PTERMDLG)GetWindowLong(hwnd, DWL_USER);
|
|
EndMdmDialog(pTerminaldialog->ParenthWnd,pTerminaldialog->idLine, TERMINAL_DLG,
|
|
(GET_WM_COMMAND_ID(wParam, lParam) == IDOK) ?
|
|
MDM_SUCCESS : MDM_HANGUP);
|
|
break;
|
|
}
|
|
};
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** Terminal Input Handler
|
|
**----------------------------------------------------------------------------
|
|
*/
|
|
|
|
BOOL NEAR PASCAL GetInput (HWND hwnd,
|
|
UINT usMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam )
|
|
{
|
|
PTERMDLG pTerminaldialog;
|
|
DWORD cbRead;
|
|
OVERLAPPED ov;
|
|
HANDLE hEvent;
|
|
COMMTIMEOUTS commtimeout;
|
|
|
|
pTerminaldialog = (PTERMDLG)GetWindowLong(hwnd, DWL_USER);
|
|
|
|
if ((hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Set write timeout to one second
|
|
//
|
|
commtimeout.ReadIntervalTimeout = MAXDWORD;
|
|
commtimeout.ReadTotalTimeoutMultiplier = 0;
|
|
commtimeout.ReadTotalTimeoutConstant = 0;
|
|
commtimeout.WriteTotalTimeoutMultiplier= 0;
|
|
commtimeout.WriteTotalTimeoutConstant = 1000;
|
|
SetCommTimeouts(pTerminaldialog->hport, &commtimeout);
|
|
|
|
do
|
|
{
|
|
/* Make sure we still have the comm port
|
|
*/
|
|
if (pTerminaldialog->hport == NULL)
|
|
break;
|
|
|
|
/* A character has been received from the device.
|
|
*/
|
|
ov.Internal = 0;
|
|
ov.InternalHigh = 0;
|
|
ov.Offset = 0;
|
|
ov.OffsetHigh = 0;
|
|
ov.hEvent = (HANDLE)((DWORD)hEvent | 1);
|
|
|
|
cbRead = 0;
|
|
|
|
if (FALSE == ReadFile(pTerminaldialog->hport,
|
|
pTerminaldialog->pbyteReceiveBuf,
|
|
SIZE_ReceiveBuf, (LPDWORD)&cbRead, &ov))
|
|
{
|
|
DWORD dwResult = GetLastError();
|
|
|
|
if (ERROR_IO_PENDING == dwResult)
|
|
{
|
|
GetOverlappedResult(pTerminaldialog->hport,
|
|
&ov,
|
|
&cbRead,
|
|
TRUE);
|
|
}
|
|
else
|
|
{
|
|
DPRINTF1("ReadFile() in GetInput() failed (0x%8x)!", dwResult);
|
|
}
|
|
};
|
|
|
|
SetEvent(pTerminaldialog->hEvent[READ_EVENT]);
|
|
|
|
/* Send the device talk to the terminal edit box.
|
|
*/
|
|
if (cbRead != 0)
|
|
{
|
|
char szBuf[ SIZE_ReceiveBuf + 1 ];
|
|
#ifdef UNICODE
|
|
WCHAR szUnicodeBuf[ SIZE_ReceiveBuf + 1 ];
|
|
#endif // UNICODE
|
|
LPSTR pch = szBuf;
|
|
int i, cb;
|
|
HWND hwndScrn = GetDlgItem(hwnd, CID_T_EB_SCREEN);
|
|
|
|
cb = cbRead;
|
|
for (i = 0; i < cb; ++i)
|
|
{
|
|
char ch = pTerminaldialog->pbyteReceiveBuf[ i ];
|
|
|
|
/* Formatting: Converts CRs to LFs (there seems to be no VK_
|
|
** for LF) and throws away LFs. This prevents the user from
|
|
** exiting the dialog when they press Enter (CR) in the
|
|
** terminal screen. LF looks like CRLF in the edit box. Also,
|
|
** throw away TABs because otherwise they change focus to the
|
|
** next control.
|
|
*/
|
|
if (ch == VK_RETURN)
|
|
{
|
|
/* Must send whenever end-of-line is encountered because
|
|
** EM_REPLACESEL doesn't handle VK_RETURN characters well
|
|
** (prints garbage).
|
|
*/
|
|
*pch = '\0';
|
|
|
|
/* Turn off current selection, if any, and replace the null
|
|
** selection with the current buffer. This has the effect
|
|
** of adding the buffer at the caret. Finally, send the
|
|
** EOL to the window which (unlike EM_REPLACESEL) handles
|
|
** it correctly.
|
|
*/
|
|
SendMessage(hwndScrn, WM_SETREDRAW, (WPARAM )FALSE, 0);
|
|
|
|
SendMessage(hwndScrn, EM_SETSEL, 32767, 32767 );
|
|
#ifdef UNICODE
|
|
if (MultiByteToWideChar(CP_ACP,
|
|
0,
|
|
szBuf,
|
|
-1,
|
|
szUnicodeBuf,
|
|
sizeof(szUnicodeBuf)))
|
|
{
|
|
SendMessage(hwndScrn, EM_REPLACESEL, 0, (LPARAM )szUnicodeBuf );
|
|
}
|
|
#else // UNICODE
|
|
SendMessage(hwndScrn, EM_REPLACESEL, 0, (LPARAM )szBuf );
|
|
#endif // UNICODE
|
|
SendMessage(hwndScrn, WM_EOLFROMDEVICE, 0, 0 );
|
|
|
|
SendMessage(hwndScrn, WM_SETREDRAW, (WPARAM )TRUE, 0);
|
|
SendMessage(hwndScrn, EM_SCROLLCARET, 0, 0);
|
|
InvalidateRect(hwndScrn, NULL, FALSE);
|
|
|
|
/* Start afresh on the output buffer.
|
|
*/
|
|
pch = szBuf;
|
|
continue;
|
|
}
|
|
else if (ch == '\n' || ch == VK_TAB)
|
|
continue;
|
|
|
|
*pch++ = ch;
|
|
}
|
|
|
|
*pch = '\0';
|
|
|
|
if (pch != szBuf)
|
|
{
|
|
/* Send the last remnant of the line.
|
|
*/
|
|
SendMessage(hwndScrn, EM_SETSEL, 32767, 32767);
|
|
#ifdef UNICODE
|
|
if (MultiByteToWideChar(CP_ACP,
|
|
0,
|
|
szBuf,
|
|
-1,
|
|
szUnicodeBuf,
|
|
sizeof(szUnicodeBuf)))
|
|
{
|
|
SendMessage(hwndScrn, EM_REPLACESEL, 0, (LPARAM)szUnicodeBuf );
|
|
}
|
|
#else // UNICODE
|
|
SendMessage(hwndScrn, EM_REPLACESEL, 0, (LPARAM)szBuf );
|
|
#endif // UNICODE
|
|
SendMessage(hwndScrn, EM_SCROLLCARET, 0, 0);
|
|
}
|
|
}
|
|
}while (cbRead != 0);
|
|
|
|
CloseHandle(hEvent);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** Terminal Output Handler
|
|
**----------------------------------------------------------------------------
|
|
*/
|
|
|
|
VOID NEAR PASCAL SendCharacter( HWND hwnd, BYTE byte )
|
|
|
|
/* Send character 'byte' to the device.
|
|
*/
|
|
{
|
|
PTERMDLG pTerminaldialog;
|
|
DWORD cbWrite;
|
|
OVERLAPPED ov;
|
|
HANDLE hEvent;
|
|
COMMTIMEOUTS commtimeout;
|
|
|
|
pTerminaldialog = (PTERMDLG)GetWindowLong(hwnd, DWL_USER);
|
|
|
|
/* Make sure we still have the comm port
|
|
*/
|
|
if (pTerminaldialog->hport == NULL)
|
|
return;
|
|
|
|
/* Send the character to the device. It is not passed thru
|
|
** because the device will echo it.
|
|
*/
|
|
pTerminaldialog->pbyteSendBuf[ 0 ] = (BYTE )byte;
|
|
|
|
// Set write timeout to one second
|
|
//
|
|
commtimeout.ReadIntervalTimeout = MAXDWORD;
|
|
commtimeout.ReadTotalTimeoutMultiplier = 0;
|
|
commtimeout.ReadTotalTimeoutConstant = 0;
|
|
commtimeout.WriteTotalTimeoutMultiplier= 0;
|
|
commtimeout.WriteTotalTimeoutConstant = 1000;
|
|
SetCommTimeouts(pTerminaldialog->hport, &commtimeout);
|
|
|
|
if ((hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) != NULL)
|
|
{
|
|
ov.Internal = 0;
|
|
ov.InternalHigh = 0;
|
|
ov.Offset = 0;
|
|
ov.OffsetHigh = 0;
|
|
ov.hEvent = (HANDLE)((DWORD)hEvent | 1);
|
|
|
|
cbWrite = 0;
|
|
|
|
if (FALSE == WriteFile(pTerminaldialog->hport,
|
|
pTerminaldialog->pbyteSendBuf,
|
|
SIZE_SendBuf, &cbWrite, &ov))
|
|
{
|
|
DWORD dwResult = GetLastError();
|
|
DWORD dwNumBytesWritten;
|
|
|
|
if (ERROR_IO_PENDING == dwResult)
|
|
{
|
|
GetOverlappedResult(pTerminaldialog->hport,
|
|
&ov,
|
|
&dwNumBytesWritten,
|
|
TRUE);
|
|
if (dwNumBytesWritten != SIZE_SendBuf)
|
|
{
|
|
DPRINTF1("WriteFile() in SendCharacter() only wrote %d bytes!",
|
|
dwNumBytesWritten);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPRINTF1("WriteFile() in SendCharacter() failed (0x%8x)!", dwResult);
|
|
}
|
|
}
|
|
|
|
CloseHandle(hEvent);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** Terminal Apperance Adjuster
|
|
**----------------------------------------------------------------------------
|
|
*/
|
|
|
|
VOID NEAR PASCAL AdjustTerminal (HWND hwnd, int wWidth, int wHeight)
|
|
{
|
|
HWND hwndCtrl;
|
|
RECT rect;
|
|
SIZE sizeButton;
|
|
POINT ptPos;
|
|
DWORD dwUnit;
|
|
|
|
// Get the sizes of the push buttons
|
|
//
|
|
dwUnit = GetDialogBaseUnits();
|
|
hwndCtrl = GetDlgItem(hwnd, IDOK);
|
|
GetWindowRect(hwndCtrl, &rect);
|
|
sizeButton.cx = rect.right - rect.left;
|
|
sizeButton.cy = rect.bottom - rect.top;
|
|
ptPos.x = wWidth/2 - ((X_SPACING*LOWORD(dwUnit))/4)/2 - sizeButton.cx;
|
|
ptPos.y = wHeight - (sizeButton.cy+((Y_MARGIN*HIWORD(dwUnit))/4));
|
|
|
|
// Move the push buttons
|
|
MoveWindow(hwndCtrl, ptPos.x, ptPos.y, sizeButton.cx, sizeButton.cy, TRUE);
|
|
|
|
ptPos.x += ((X_SPACING*LOWORD(dwUnit))/4) + sizeButton.cx;
|
|
MoveWindow(GetDlgItem(hwnd, IDCANCEL), ptPos.x, ptPos.y,
|
|
sizeButton.cx, sizeButton.cy, TRUE);
|
|
|
|
// Get the current position of the terminal screen
|
|
hwndCtrl = GetDlgItem(hwnd, CID_T_EB_SCREEN);
|
|
GetWindowRect(hwndCtrl, &rect);
|
|
ScreenToClient(hwnd, (LPPOINT)&rect);
|
|
MoveWindow(hwndCtrl, rect.left, rect.top,
|
|
wWidth - 2*rect.left,
|
|
ptPos.y - rect.top - ((Y_MARGIN*HIWORD(dwUnit))/4),
|
|
TRUE);
|
|
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
return;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** Terminal read-notification thread
|
|
**----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void WINAPI TerminalThread (PTERMDLG pTerminaldialog)
|
|
{
|
|
DWORD dwEvent;
|
|
DWORD dwMask;
|
|
|
|
while((dwEvent = WaitForMultipleObjects(MAX_EVENT, pTerminaldialog->hEvent,
|
|
FALSE, INFINITE))
|
|
< WAIT_OBJECT_0+MAX_EVENT)
|
|
{
|
|
switch (dwEvent)
|
|
{
|
|
case READ_EVENT:
|
|
|
|
// If we are stopped already, just get out of here
|
|
//
|
|
if (WaitForSingleObject(pTerminaldialog->hEvent[STOP_EVENT], 0)
|
|
== WAIT_TIMEOUT)
|
|
{
|
|
dwMask = 0;
|
|
WaitCommEvent(pTerminaldialog->hport, &dwMask, NULL);
|
|
|
|
if ((dwMask & EV_RXCHAR) && (pTerminaldialog->hwnd != NULL))
|
|
{
|
|
PostMessage(pTerminaldialog->hwnd, WM_MODEMNOTIFY, 0, 0);
|
|
};
|
|
break;
|
|
};
|
|
|
|
case STOP_EVENT:
|
|
ExitThread(ERROR_SUCCESS);
|
|
break;
|
|
};
|
|
};
|
|
}
|