📄 chapt13.cpp
字号:
//
// CHAPT13.CPP
//
// Source code from:
//
// Serial Communications: A C++ Developer's Guide, 2nd Edition
// by Mark Nelson, IDG Books, 1999
//
// Please see the book for information on usage.
//
// This file contains the source code for the Chapter 13
// demo program. To build this file, use the Visual C++
// project file included in the same directory as the
// sample code.
//
#include <windows.h>
#include "AnsiWinTerm.h"
#include "resource.h"
LRESULT CALLBACK WinProc( HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam );
//
// The WinMain() function for this program looks
// very generic. It has to register the class we
// will create for this demo program, being sure
// to include our menu and WinProc. Once the class
// is registered, we can just create the window and
// let it do all the rest of the work. From that
// point on, all we have to do in this routine is
// run the message loop until somebody decides it's
// time to exit.
//
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE /* hPrevInstance */,
LPSTR /* lpCmdLine */,
int nShowCmd )
{
//
// Note that we store enough space extra in our class
// to hold a single pointer. We keep a pointer to our
// child window in that extra space, allowing us to
// avoid the bad taste associated with global variables.
//
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WinProc;
wc.hInstance = hInstance;
wc.lpszMenuName = MAKEINTRESOURCE( IDR_MENU );
wc.hbrBackground = (HBRUSH) ( COLOR_WINDOW + 1 );
wc.lpszClassName = "Chapter13Class";
wc.cbWndExtra = sizeof( Win32Term * );
if ( !RegisterClass( &wc ) ) {
MessageBox( NULL, "Could not register Chapter 13 class!", NULL, MB_OK );
return 0;
}
HWND hwnd = CreateWindow( "Chapter13Class",
"Chapter 13 Test Program",
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT,
CW_USEDEFAULT,
647, // hand picked size to fit exactly 25 x 80
347,
NULL,
NULL,
hInstance,
NULL );
if ( hwnd == NULL ) {
MessageBox( NULL, "Chapter13.exe couldn't start!", NULL, MB_OK );
return 0;
}
ShowWindow( hwnd, nShowCmd );
UpdateWindow( hwnd );
MSG msg;
while ( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg ) ;
DispatchMessage( &msg ) ;
}
return 1;
}
//
// Each time I open or close the port I have to
// change the enabled status of five menu items.
// Namely, the four Open COMx entries and the one
// Close Port entry. This routine does the work,
// and does it properly regardless of whether we
// just opened or just closed a port.
//
void UpdateMenu( HWND hwnd, bool port_open )
{
HMENU menu = ::GetMenu( hwnd );
if ( menu ) {
::EnableMenuItem( menu, ID_PORT_OPEN_COM1, port_open ? MF_GRAYED : MF_ENABLED );
::EnableMenuItem( menu, ID_PORT_OPEN_COM2, port_open ? MF_GRAYED : MF_ENABLED );
::EnableMenuItem( menu, ID_PORT_OPEN_COM3, port_open ? MF_GRAYED : MF_ENABLED );
::EnableMenuItem( menu, ID_PORT_OPEN_COM4, port_open ? MF_GRAYED : MF_ENABLED );
::EnableMenuItem( menu, ID_PORT_CLOSE, port_open ? MF_ENABLED : MF_GRAYED );
}
}
//
// This is the WinProc for the sample program. Fortunately for
// the sake of clarity, all of the things that have to do with
// terminal emulation are being handled by the Window Procedures
// in the terminal emulation window. All we have to handle in
// this procedure are menu commands and a few administrative
// details.
//
// Note that the pointer to the Terminal Emulation window is
// stored as a Window Long word. Each time I enter the loop,
// I extract that pointer for use in all the various message
// handlers in this routine.
//
LRESULT CALLBACK WinProc( HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam )
{
//
// The custom color array is here so that I can support
// the custom colors in my ChooseColor dialog.
//
static COLORREF custom_colors[ 16 ] = { 0 };
AnsiWinTerm *pTerm = (AnsiWinTerm *) ::GetWindowLong( hWnd, 0 );
switch ( message )
{
//
// When my window is first created, I immediately
// create the terminal window as a child window. I
// get the pointer to the C++ object and store it as
// a window long word, giving me access to it whenever
// I need it without using a global variable.
//
case WM_CREATE:
pTerm = new AnsiWinTerm( hWnd, "AnsiTerm Window", 25, 80 );
SetWindowLong( hWnd, 0, (LONG) pTerm );
if ( pTerm->m_hWnd == NULL )
MessageBox( hWnd, "Can't open child window", "Chapter 13", MB_OK );
SetFocus( hWnd );
break;
//
// When I am being destroyed, I take it upon myself to
// destroy the terminal object as well. Note that simply
// calling the C++ destructor like I'm doing here isn't
// necessarily enough to destory the window itself, but
// since it is a child window the O/S will do that in
// good time.
//
case WM_DESTROY:
delete pTerm;
pTerm = 0;
PostQuitMessage( 0 );
break;
//
// Just for the sake of esthetics, I respond to this message
// with a minimum size large enough to prevent somebody from
// resizing me down to the point of ridiculousness.
//
case WM_GETMINMAXINFO:
{
LPMINMAXINFO lp = (LPMINMAXINFO) lParam;
POINT ptTemp = {
lp->ptMinTrackSize.x,
GetSystemMetrics( SM_CYMENU ) +
GetSystemMetrics( SM_CYCAPTION ) +
2 * GetSystemMetrics( SM_CYFRAME )
};
lp->ptMinTrackSize = ptTemp;
}
break;
//
// When the frame window is resized, I immediately
// resize the terminal window. Size the terminal window
// is supposed to completely fill my client area, I
// can figure out what size it is supposed to be by
// simply getting the size of my client rect. When
// the terminal window processes this command it will
// potentially add scroll bars and offset the display.
//
case WM_SIZE:
{
RECT rc;
::GetClientRect( hWnd, &rc );
if ( lParam != 0 )
::MoveWindow( pTerm->m_hWnd,
0, 0,
rc.right - rc.left + 1,
rc.bottom - rc.top + 1,
TRUE );
}
break;
//
// I don't want the framing window to get the focus,
// so whenever I get it, I immediately foist it upon
// the terminal window.
//
case WM_SETFOCUS :
SetFocus( pTerm->m_hWnd );
return 0;
//
// The rest of the code in the message loop
// is the set of command handlers for menu
// items.
//
case WM_COMMAND:
switch ( LOWORD( wParam ) ) {
//
// Clearing the temrinal window is simply a
// matter of calling one member function
//
case ID_TERMINAL_CLEAR :
pTerm->Clear();
break;
//
// Telling a window to close itself is a fast way
// of shutting the program down.
//
case ID_FILE_EXIT :
PostMessage( hWnd, WM_CLOSE, 0, 0 );
break;
//
// The four Open COMx routines all do essentially
// the same thing: attempt to open the port, and
// if succesful, modify the menu a bit. Note that
// the port is actually being opened inside the
// terminal object, we're calling a wrapper routine
// here.
//
case ID_PORT_OPEN_COM1 :
if ( pTerm->OpenPort( "COM1" ) )
UpdateMenu( hWnd, true );
break;
case ID_PORT_OPEN_COM2 :
if ( pTerm->OpenPort( "COM2" ) )
UpdateMenu( hWnd, true );
break;
case ID_PORT_OPEN_COM3 :
if ( pTerm->OpenPort( "COM3" ) )
UpdateMenu( hWnd, true );
break;
case ID_PORT_OPEN_COM4 :
if ( pTerm->OpenPort( "COM4" ) )
UpdateMenu( hWnd, true );
break;
//
// Closing the port is another one of those one
// line of code things. Note that we assume that
// we will never get this command unless the port
// is already open. We believe that is the case
// because we never enable the Close item on the
// menu while the port is closed.
//
case ID_PORT_CLOSE :
pTerm->ClosePort();
UpdateMenu( hWnd, false );
break;
//
// The Set Font command is really pretty simple, it's
// just a little longer because it has to do a bit of
// setup work to call the ChooseFont() dialog. You can
// see in this routine that if the person presses the
// OK button in the font dialog, the SetFont() member
// of the terminal emulator will be called with a copy
// of the new LOGFONT settings.
//
case ID_TERMINAL_SET_FONT:
{
CHOOSEFONT cf = {0};
LOGFONT lf = pTerm->GetLogFont();
cf.lStructSize = sizeof( CHOOSEFONT );
cf.hwndOwner = hWnd;
cf.lpLogFont = &lf;
cf.Flags = CF_INITTOLOGFONTSTRUCT |
CF_SCREENFONTS |
CF_FIXEDPITCHONLY;
if ( !ChooseFont( &cf ) )
break;
pTerm->SetFont( lf );
break;
}
//
// The three remaining routines are all pretty
// much the same. They choose a color, then pass
// it to the terminal emulator via a function call.
// Note that the two text routines won't have an
// immediate noticeable effect, that doesn't happen
// until more text arrives. Setting the border color
// on the other hand, will cause an immediate change
// to appear.
//
case ID_TERMINAL_SET_TEXT_COLOR :
{
CHOOSECOLOR cc = { 0 };
cc.lStructSize = sizeof( CHOOSECOLOR );
cc.hwndOwner = hWnd;
cc.rgbResult = pTerm->GetForegroundColor();
cc.Flags = CC_ANYCOLOR | CC_RGBINIT;
cc.lpCustColors = custom_colors;
if ( ChooseColor( &cc ) )
pTerm->SetForegroundColor( cc.rgbResult );
}
break;
case ID_TERMINAL_SET_BACKGROUND_COLOR :
{
CHOOSECOLOR cc = { 0 };
cc.lStructSize = sizeof( CHOOSECOLOR );
cc.hwndOwner = hWnd;
cc.rgbResult = pTerm->GetBackgroundColor();
cc.Flags = CC_ANYCOLOR | CC_RGBINIT;
cc.lpCustColors = custom_colors;
if ( ChooseColor( &cc ) )
pTerm->SetBackgroundColor( cc.rgbResult );
}
break;
case ID_TERMINAL_SET_BORDER_COLOR :
{
CHOOSECOLOR cc = { 0 };
cc.lStructSize = sizeof( CHOOSECOLOR );
cc.hwndOwner = hWnd;
cc.rgbResult = pTerm->GetBorderColor();
cc.Flags = CC_ANYCOLOR | CC_RGBINIT;
cc.lpCustColors = custom_colors;
if ( ChooseColor( &cc ) )
pTerm->SetBorderColor( cc.rgbResult );
}
break;
}
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
return 0L;
}
// End of CHAPT13.CPP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -