📄 cppterminal.cpp
字号:
// CPPTerminal.cpp : Simple Terminal using a console.
// The application asks the user for connection information and then allows line by
// line input to the device. Data returned is signaled by a read event and sent to
// the standard output. This is an example of how a non-MFC C++ program can directly
// use the Terminal Interface, and by inference, all other interfaces. The example
// shows how to call a COM in-process server interface and take advantage of connection points.
//
// Include Files
// STL for strings and IO
#include <string>
#include <iostream>
#include <sstream>
#include <limits>
//using namespace std; // uncomment this statement to avoid putting std:: everywhere
// ATL for easier use of COM
#define _WIN32_DCOM // Before windows.h, allows CoInitializeEx()
#include <windows.h>
#include <atlbase.h>
CComModule _Module;
#include <atlcom.h>
#undef max // max is a windows macro (bad), but I need to use the max in STL
// Import the BoxBridge Type Library to make COM stuff a bit easier to read
#import "..\ComACRsrvr.tlb" no_namespace named_guids
// ATL defined structure for defining the parameter data of the callback.
// In this case there are no prameters.
_ATL_FUNC_INFO ReadAlertInfo = {CC_STDCALL, VT_EMPTY, 0, {VT_EMPTY}};
//-----------------------------------------------------------------------------
// Connection Points are really callbacks, so we have to implement a COM method
// that can be called from the automation server. Using a class lets us inherit
// from the ATL template, saving us the pain of implementing the generic interfaces.
//-----------------------------------------------------------------------------
class CReadEvent:
public IDispEventSimpleImpl<1, CReadEvent, &DIID__ITerminalEvents>
{
// The CReadEvent will provide a callback for the DataWaiting Event on the Terminal
// Interface. When it is called, there is data waiting to be read, so the method
// reads the data and sends it to the standard output. All code in this class is
// done inline for ease of reading.
public:
CReadEvent(ITerminalPtr term)
{
// This class uses a passed in smart pointer that is already connected to establish
// communications. Another way to do this would be to pass in the connection state
// information, create a new object reference and connect. This is show in the
// CPPControl sample. A third way would be to use global variables to hold the
// interface pointers.
// This is another reference to a smart pointer, so it must be set to NULL in the destructor
m_Term = term;
HRESULT hr = DispEventAdvise((IUnknown*)m_Term);
}
virtual ~CReadEvent()
{
DispEventUnadvise((IUnknown*)m_Term);
m_Term = NULL; // Setting smart pointers to NULL is *VERY IMPORTANT*
}
void __stdcall ReadAlert()
{
// Data is waiting to be read, send it to the std out
try{
m_Read = m_Term->Read();
std::cout << _com_util::ConvertBSTRToString(m_Read);
}catch(...){ return; /*ignore errors here*/ }
}
// The IDL used for this event is:
//
// [ uuid(A1C9E9E2-49BB-40A8-8A9B-301051D224F2),
// helpstring("_ITerminalEvents Interface")]
// dispinterface _ITerminalEvents
// { properties:
// methods:
// [id(1), helpstring("Data Waiting to be Read")] HRESULT DataWaiting();
// };
//
// Information mapped by the ATL class (above) supports Connection Points.
//
BEGIN_SINK_MAP(CReadEvent)
SINK_ENTRY_INFO(1, DIID__ITerminalEvents, 1, ReadAlert, &ReadAlertInfo)
END_SINK_MAP()
private:
ITerminalPtr m_Term; // smart pointer from #import
_bstr_t m_Read; // hold data read from device
};
void getInputLong(long &in, const std::string &msg, const long inMin = 0, const long inMax = 0) {
// The cin has problems if the proper type of data is not entered, so
// handel those issues in one place. Since most of the cin is in the
// main(), this is a global function, but could also be a class method.
while (!(std::cin >> in) || ((inMax > inMin) && (in < inMin || in > inMax))) {
std::cout << msg;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
//-----------------------------------------------------------------------------
// Main Terminal Loop
//-----------------------------------------------------------------------------
int main(int argc, char* argv[])
{
// The Terminal Interface pointer is here (before the try) to allow easy clean up in
// main()'s try/catch. It is important to set any smart pointers to NULL before exiting.
ITerminalPtr gTerm;
CReadEvent* alert = NULL;
try{
// Need to initialize for each thread as multithreaded
CoInitializeEx(NULL, COINIT_MULTITHREADED);
// Establish Communication Server
gTerm.CreateInstance(CLSID_Terminal);
std::string ver = std::string(_com_util::ConvertBSTRToString(gTerm->bstrVersion)); // Version
std::cout << "--------Simple Terminal using the BoxBridge v" << ver << "--------\n\n";
// Collect Connection Information
long transport = 0; // transport type
std::string portname; // transport lable
long busType = 0; // bus type
long portNbr = 1; // com port
long portBPS = 2; // bps of com port
std::string ipaddr; // ip address
long cardNbr = 0; // card index
std::string input; // terminal input
long bps[3] = {9600,19200,38400}; // bps values
std::cout << "How are we connecting. Type in a number and press <enter>\n1=Bus, 2=Serial, 3=Ethernet, 4=USB: ";
getInputLong(transport, "You must enter a number between 0 - 4: ",0,4);
switch (transport){
// Various transport types require specific extra communication data
case 0:
portname = "OFFLINE";
break;
case 1:
portname = "BUS";
std::cout << "What Type of bus is the device in?\n0=PCI, 1=ISA: ";
getInputLong(busType, "You must enter a number between 0 - 1: ",0,1);
std::cout << "What is the index number of the device (usually 0):";
getInputLong(cardNbr, "You must enter a number: ");
break;
case 2:
portname = "SERIAL";
std::cout << "What is the Com Port number: ";
getInputLong(portNbr, "You must enter a number between 1 - 256: ",1,256);
std::cout << "What is the BPS of the Com Port? 0=9600, 1=19200, 2=38400: ";
getInputLong(portBPS, "You must enter a number between 0 - 2: ",0,2);
std::cout << "What is the index number of the device (usually 0): ";
getInputLong(cardNbr, "You must enter a number: ");
break;
case 3:
portname = "ETHERNET";
std::cout << "What is the ip address of the device: ";
std::cin >> ipaddr;
std::cout << "What is the index number of the device (usually 0): ";
getInputLong(cardNbr, "You must enter a number: ");
break;
case 4:
portname = "USB";
std::cout << "What is the index number of the device (usually 0): ";
getInputLong(cardNbr, "You must enter a number: ");
break;
default:
portname = "Unknown";
transport = 0;
break;
}
// Connect to Device
gTerm->nBus = busType;
gTerm->nPort = portNbr;
gTerm->nBPS = bps[portBPS];
gTerm->bstrIP = _bstr_t(ipaddr.c_str());
std::cout << "\nConnecting...";
gTerm->Connect(transport,cardNbr);
if(gTerm->isOffline){
std::cout << "you have choosen not to connect, goodbye" << std::endl;
return 0;
}
std::cout << "you are now connected using the " << portname << " port.\n\nEnter the word QUIT (in UPPER CASE) to exit.\n\n";
// Initialize Read Event
gTerm->Write(_bstr_t("echo0\r")); // data is echoed locally in this terminal
Sleep(100);
_bstr_t dummy = gTerm->Read(); // clear out read buffer
alert = new CReadEvent(gTerm); // start reading
gTerm->Write(_bstr_t("ver\r")); // display device version
// The Terminal - line based data entry (i.e. type in stuff and hit enter to submit.)
while ((std::cin >> input) && (input != "QUIT")){
input += '\r';
gTerm->Write(_bstr_t(input.c_str())); // write out characters
}
// Close the COM stuff down
gTerm->Disconnect();
delete alert;
gTerm = NULL; // Setting smart pointers to NULL is *VERY IMPORTANT*
CoUninitialize();
return 0;
// Error Handling - the errors specifically thrown by Communications Server
// show up as COM exceptions and can be caught with the _com_error class.
}catch(_com_error err){
delete alert;
gTerm = NULL; // Setting smart pointers to NULL is *VERY IMPORTANT*
CoUninitialize();
MessageBox(NULL, err.Description(), "COM Error", MB_OK);
return 0;
}catch(...){
delete alert;
gTerm = NULL; // Setting smart pointers to NULL is *VERY IMPORTANT*
CoUninitialize();
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR) &lpMsgBuf,0,NULL);
MessageBox(NULL, (LPCTSTR)lpMsgBuf, "General Error", MB_OK);
LocalFree(lpMsgBuf);
return 0;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -