📄 cppstatus.cpp
字号:
// CPPStatus.cpp : Simple Status parameter watch using a console.
// The application asks the user for connection information and a p-Parameter to watch.
// If that p-Parameter changes, the application is signaled by a status event and the
// value of the p-Parameter is read. 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 StatAlertInfo = {CC_STDCALL, VT_EMPTY, 2, {VT_I4, VT_I4}};
//-----------------------------------------------------------------------------
// 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 CStatEvent:
public IDispEventSimpleImpl<1, CStatEvent, &DIID__IStatusEvents>
{
// The CStatEvent will provide a callback for the StatusWaiting Event on the Status
// 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:
CStatEvent(IStatusPtr stat)
{
// 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_Stat = stat;
HRESULT hr = DispEventAdvise((IUnknown*)m_Stat);
}
virtual ~CStatEvent()
{
DispEventUnadvise((IUnknown*)m_Stat);
m_Stat = NULL; // Setting smart pointers to NULL is *VERY IMPORTANT*
}
void __stdcall StatAlert(long msgId, long errNbr)
{
// Data is waiting to be read, send it to the std out
try{
// Init SafeArray Stuff
SAFEARRAY* pSA;
long lBound = 0;
CComVariant vItem; // The CComVariant is found in the atlbase.h include file
CComVariant status; // it will clean up SAFEARRAY when it goes out of scope.
// Read and display status (there could be more than one status value in
// the returned array, but this sample just shows the first one.
status = m_Stat->GetStatus(msgId);
if(status.vt & VT_ARRAY){
pSA = status.parray;
SafeArrayGetElement(pSA, &lBound, &vItem);
if(vItem.vt==VT_I4)
std::cout << "Value in message id" << msgId << " is now " << vItem.lVal << '\n';
if(vItem.vt==VT_R4)
std::cout << "Value in message id" << msgId << " is now " << vItem.fltVal << '\n';
}
}catch(...){ return; /*ignore errors here*/ }
}
// The IDL used for this event is:
//
// [ uuid(548F6282-AEE7-4AFA-B1F6-8C85389DD697),
// helpstring("_IStatusEvents Interface")]
// dispinterface _IStatusEvents
// { properties:
// methods:
// [id(1), helpstring("Status Waiting")] HRESULT StatusWaiting([in] long msgID, [in] long error);
// };
//
// Information mapped by the ATL class (above) supports Connection Points.
//
BEGIN_SINK_MAP(CStatEvent)
SINK_ENTRY_INFO(1, DIID__IStatusEvents, 1, StatAlert, &StatAlertInfo)
END_SINK_MAP()
private:
IStatusPtr m_Stat; // smart pointer from #import
};
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 Interface pointers are 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.
IStatusPtr gStat;
CStatEvent* alert = NULL;
try{
// Need to initialize for each thread as multithreaded
CoInitializeEx(NULL, COINIT_MULTITHREADED);
// Establish Communication Server
gStat.CreateInstance(CLSID_Status);
std::string ver = std::string(_com_util::ConvertBSTRToString(gStat->bstrVersion)); // Version
std::cout << "--------Simple Status Watch 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::string pparm; // parameter to monitor
std::cout << "How are we connecting. Type in a number and press <enter>\n0=Offline, 1=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
gStat->nBus = busType;
gStat->nPort = portNbr;
gStat->nBPS = bps[portBPS];
gStat->bstrIP = _bstr_t(ipaddr.c_str());
std::cout << "\nConnecting...";
gStat->Connect(transport,cardNbr);
if(gStat->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\n";
std::cout << "Use the Upper Case S key followed by <Enter> to stop watching a parameter.\n";
std::cout << "Use the Upper Case Q key followed by <Enter> to quit.\n\n";
// p6916 is the global system clock and will generate lots of events.
std::cout << "What p-Parameter would you like to monitor (enter in the form P6916): ";
std::cin >> pparm;
// Initialize Status Event and add in Status request
alert = new CStatEvent(gStat);
// The AddACRCustom allows up to 32 p-Parameters per status request, but this
// sample will only display the first value entered.
long MessageID = gStat->AddACRCustom(_bstr_t(pparm.c_str()));
std::cout << std::endl;
std::cout << "Parameter " << pparm << " has been added under message id:" << MessageID << std::endl;
// The interactive loop (i.e. type in stuff and hit enter to submit.)
while ((std::cin >> input) && (input != "Q")){
if(input == "S"){
gStat->DelStatus(MessageID);
std::cout << "The pparm added under message id:" << MessageID << " has been stopped.\n\n";
std::cout << "What p-Parameter would you like to monitor (enter in the form P6916): ";
std::cin >> pparm;
long MessageID = gStat->AddACRCustom(_bstr_t(pparm.c_str()));
std::cout << "Parameter " << pparm << " has been added under message id:" << MessageID << std::endl;
}
}
// Close the COM stuff down
gStat->DelStatus(MessageID);
gStat->Disconnect();
delete alert;
gStat = 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;
gStat = NULL; // Setting smart pointers to NULL is *VERY IMPORTANT*
CoUninitialize();
MessageBox(NULL, err.Description(), "COM Error", MB_OK);
return 0;
}catch(...){
delete alert;
gStat = 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 + -