📄 server.cpp
字号:
// Instantiate a new CKGroup (with this server as it's parent):
pGroup = new CKGroup (this);
// Call the group's serialize function so that it can read
// its properties from the archive:
pGroup->Serialize (ar);
// New groups are added to the head of the linked list.
// That means new the groups's "next" group is old head of list,
pGroup->SetNext (m_pGroupHead);
// and the new group is the old head of list's "previous" group,
if (m_pGroupHead)
m_pGroupHead->SetPrev (pGroup);
// and that new group is now the new "head" of list.
m_pGroupHead = pGroup;
}
catch (...)
{
// There was a problem reading group properties. Delete
// this object and throw another exception. This exception
// must be handled by the calling function.
delete this;
AfxThrowArchiveException (CArchiveException::generic);
}
}
break;
default:
// Unexpected archive version. Delete this object and
// throw an exception that indicates this. This exception
// must be handled by the calling function.
delete this;
AfxThrowArchiveException (CArchiveException::badSchema);
break;
}
}
}
// **************************************************************************
// Start ()
//
// Description:
// Connect to OPC Server, then add and start all its OPC Groups.
//
// Parameters:
// none
//
// Returns:
// void
// **************************************************************************
void CKServer::Start ()
{
// Attempt to connect to the OPC Server:
Connect ();
// Regardless of connection success, add the groups. (They will be added
// invalid (i.e, for edits) if the server is not connected.)
// Start with head of linked list:
CKGroup *pGroup = m_pGroupHead;
// Keep looping we hit the end of the link list (where pGroup will be NULL):
while (pGroup)
{
// Add the group to OPC Server. (Second argument is "true" which will
// prevent the group from being added to our group list again.):
AddGroup (pGroup, true);
// Start the group:
pGroup->Start ();
// Look at next group in list next time around:
pGroup = pGroup->GetNext ();
}
}
// **************************************************************************
// Stop ()
//
// Description:
// Remove all OPC Groups from OPC Server and disconnect. Our CKGroup
// objects will not be deleted at this point. We will delete them when
// they are actually removed from project.
//
// Parameters:
// none
//
// Returns:
// void
// **************************************************************************
void CKServer::Stop ()
{
// Remove all OPC Groups. Passing "false" will prevent our CKGroups
// from being deleted.
RemoveAllGroups (false);
// Disconnect from the OPC Server we are connected to:
Disconnect ();
}
// **************************************************************************
// Copy ()
//
// Description:
// Copy server properties to shared memory file.
//
// Parameters:
// CFixedSharedFile &sf Shared memory file to copy properties to.
//
// Returns:
// void
// **************************************************************************
void CKServer::Copy (CFixedSharedFile &sf)
{
int nLen;
// Since we are saving data to a shared memory file, we can not take
// advantage of the "smarts" built into the CArchive class like we do
// in Serialize(). Consequently, to save a string, we must first save
// its length as an integer, followed by the characters in the string
// as TCHAR's.
// Save the prog ID string:
nLen = m_strProgID.GetLength ();
sf.Write (&nLen, sizeof (nLen));
sf.Write (m_strProgID, nLen * sizeof (TCHAR));
// Save the remote machine name string:
nLen = m_strRemoteMachine.GetLength ();
sf.Write (&nLen, sizeof (nLen));
sf.Write (m_strRemoteMachine, nLen * sizeof (TCHAR));
// Save the flag bit field:
sf.Write (&m_bfFlags, sizeof (m_bfFlags));
// Save the number of groups so we'll know how many to read later:
sf.Write (&m_cdwGroups, sizeof (m_cdwGroups));
// Add all of our groups' properties:
// Start with the head of linked list and work our way through the chain:
CKGroup *pGroup = m_pGroupHead;
// Keep looping until we reach end of linked list (pGroup will be NULL):
while (pGroup)
{
// Call group's copy function so it will add its properties to
// shared memory file:
pGroup->Copy (sf);
// Process next group in list next time around:
pGroup = pGroup->GetNext ();
}
}
// **************************************************************************
// Paste ()
//
// Description:
// Assign properties from shared memory file.
//
// Parameters:
// CFixedSharedFile &sf Shared memory file to get properties from.
//
// Returns:
// void
// **************************************************************************
void CKServer::Paste (CFixedSharedFile &sf)
{
int nLen;
// Since we are reading data from a shared memory file, we can not take
// advantage of the "smarts" built into the CArchive class like we do
// in Serialize(). Consequently, to read a string, we must first read
// its length as an integer, the read that many characters as TCHAR's.
// Read the prog ID string:
sf.Read (&nLen, sizeof (nLen));
sf.Read (m_strProgID.GetBufferSetLength (nLen), nLen * sizeof (TCHAR));
// Read the remote machine name string:
sf.Read (&nLen, sizeof (nLen));
sf.Read (m_strRemoteMachine.GetBufferSetLength (nLen), nLen * sizeof (TCHAR));
// Read the flag bit field:
sf.Read (&m_bfFlags, sizeof (m_bfFlags));
// Read the group count:
sf.Read (&m_cdwGroups, sizeof (m_cdwGroups));
// Add the groups:
// Start with an empty linked list:
ASSERT (m_pGroupHead == NULL);
// Loop over expected number of groups:
for (DWORD dwIndex = 0; dwIndex < m_cdwGroups; dwIndex++)
{
CKGroup *pGroup = NULL;
// Wrap group paste with exception handler in case there is a problem:
try
{
// Instantiate a new CKGroup (with this server as it's parent):
pGroup = new CKGroup (this);
// Call the group's paste function so that it can read its
// properties from the shared memory file:
pGroup->Paste (sf);
// New groups are added to the head of the linked list.
// That means new the groups's "next" group is old head of list,
pGroup->SetNext (m_pGroupHead);
// and the new group is the old head of list's "previous" group,
if (m_pGroupHead)
m_pGroupHead->SetPrev (pGroup);
// and that new group is now the new "head" of list.
m_pGroupHead = pGroup;
}
catch (...)
{
// There was a problem reading group properties.
ASSERT (FALSE);
}
}
}
/////////////////////////////////////////////////////////////////////////////
// CKServer OPC Specifics
/////////////////////////////////////////////////////////////////////////////
// **************************************************************************
// GetCLSID ()
//
// Description:
// Get the Class ID of server.
//
// Parameters:
// CLSID &clsid Class ID.
//
// Returns:
// HRESULT - use FAILED or SUCCEEDED macro to test.
// **************************************************************************
HRESULT CKServer::GetCLSID (CLSID &clsid)
{
// Local CLSID
if (m_strRemoteMachine.IsEmpty ())
{
#ifdef UNICODE
return (CLSIDFromProgID (m_strProgID, &clsid));
#else
WCHAR wszProgID [DEFBUFFSIZE];
if (!MultiByteToWideChar (CP_ACP, 0, m_strProgID, -1, wszProgID, sizeof (wszProgID) / sizeof (WCHAR)))
{
ASSERT (FALSE);
}
return (CLSIDFromProgID (wszProgID, &clsid));
#endif
}
// Remote CLSID - Use OPCENUM.EXE
else
{
COSERVERINFO tServerInfo;
ZeroMemory (&tServerInfo, sizeof (tServerInfo));
#ifdef _UNICODE
tServerInfo.pwszName = (LPTSTR)(LPCTSTR)m_strRemoteMachine;
#else
int nSize = _tcslen (m_strRemoteMachine) + 1;
tServerInfo.pwszName = (WCHAR *)CoTaskMemAlloc (sizeof (WCHAR) * nSize);
mbstowcs (tServerInfo.pwszName, m_strRemoteMachine, nSize);
#endif
// Interfaces of interest
MULTI_QI arrMultiQI [1] = {&IID_IOPCServerList, NULL, 0};
// Connect to the OPC server browser
HRESULT hr = CoCreateInstanceEx (CLSID_OPCServerList, NULL, CLSCTX_SERVER, &tServerInfo, _countof (arrMultiQI), arrMultiQI);
#ifndef _UNICODE
// Free ansi conversion buffer
if (tServerInfo.pwszName)
CoTaskMemFree (tServerInfo.pwszName);
#endif
if (FAILED (hr))
return (hr);
IOPCServerList *pIOPCServerList = (IOPCServerList *)arrMultiQI [0].pItf;
arrMultiQI [0].pItf = NULL;
// Retrieve the CLSID
#ifdef UNICODE
hr = pIOPCServerList->CLSIDFromProgID (m_strProgID, &clsid);
#else
WCHAR wszProgID [DEFBUFFSIZE];
if (!MultiByteToWideChar (CP_ACP, 0, m_strProgID, -1, wszProgID, sizeof (wszProgID) / sizeof (WCHAR)))
{
ASSERT (FALSE);
}
hr = pIOPCServerList->CLSIDFromProgID (wszProgID, &clsid);
#endif
// Disconnect from the OPC server browser
pIOPCServerList->Release ();
// Return result code
return (hr);
}
}
// **************************************************************************
// IsAlive ()
//
// Description:
// Called to test connection to server.
//
// Parameters:
// none
//
// Returns:
// bool - true if connection is live.
// **************************************************************************
bool CKServer::IsAlive ()
{
// Assume server connection is dead:
bool bAlive = false;
// If we don't think we are connected, i.e. m_bConnected or m_pIServer is
// NULL, then there is no need to test connection.
if (m_bConnected && m_pIServer)
{
// We think we are connected. Let's test that...
// Wrap our test in exception handler just in case we get a bad pointer:
try
{
OPCSERVERSTATUS *pStatus;
// Use the Get status member function of the IOPCServer interface
// to test connection. If this succeeds, then we know connection
// is alive.
if (SUCCEEDED (m_pIServer->GetStatus (&pStatus)))
{
// COM requires us to free memory allocated for [out] and [in/out]
// arguments (i.e. vender info string and pStatus)
if (pStatus->szVendorInfo)
CoTaskMemFree (pStatus->szVendorInfo);
CoTaskMemFree (pStatus);
// Don't forget to set the return status to "true":
bAlive = true;
}
}
catch (...)
{
ASSERT (FALSE);
bAlive = false;
}
}
return (bAlive);
}
// **************************************************************************
// Connect ()
//
// Description:
// Connect to OPC Server. OPC Server's ProgID and machine name must have
// been previously specified.
//
// Parameters:
// none
//
// Returns:
// bool - true if success.
// **************************************************************************
bool CKServer::Connect ()
{
// Program ID of OPC Server should have been defined by now:
ASSERT (!m_strProgID.IsEmpty ());
// Assume we are not connecting to KEPServerEx:
m_bfFlags.bIsKepServerEx = false;
// Perform any necessary cleanup from a previous connection:
Disconnect ();
// Obtain the Class ID of the OPC Server. (GetCLSID() will need the
// OPC Server's Program ID to succeed. That's why we checked it above.)
CLSID clsid;
if (SUCCEEDED (GetCLSID (clsid)))
{
HRESULT hr;
// Re-intialize Multi-Query Interface:
for (int i = 0; i < sizeof (m_arrMultiQI) / sizeof (MULTI_QI); i++)
{
m_arrMultiQI [i].pItf = NULL;
m_arrMultiQI [i].hr = 0;
}
// Load up the Interface ID's we hope to get pointers for when we
// call CoCreateInstanceEx():
m_arrMultiQI [MQI_IOPCSERVER].pIID = &IID_IOPCServer;
m_arrMultiQI [MQI_IOPCCOMMON].pIID = &IID_IOPCCommon;
m_arrMultiQI [MQI_IOPCCONNPT].pIID = &IID_IConnectionPointContainer;
m_arrMultiQI [MQI_IOPCITEMPROP].pIID = &IID_IOPCItemProperties;
m_arrMultiQI [MQI_IOPCBROWSE].pIID = &IID_IOPCBrowseServerAddressSpace;
m_arrMultiQI [MQI_IOPCPUBLIC].pIID = &IID_IOPCServerPublicGroups;
m_arrMultiQI [MQI_IOPCPERSIST].pIID = &IID_IPersistFile;
// Connect to the OPC Server and query all possible interfaces:
if (m_strRemoteMachine.IsEmpty ())
{
// Since m_strRemoteMachine is empty, we will try to instantiate
// the OPC Server on our local machine.
// CoCreateInstanceEx will launch the OPC Server if necessary, and
// call its QueryInterface for us (bumping its reference count):
hr = CoCreateInstanceEx (
clsid, // CLSID
NULL, // No aggregation
CLSCTX_SERVER, // connect to local, inproc and remote servers
NULL, // remote machine name
sizeof (m_arrMultiQI) / sizeof (MULTI_QI), // number of IIDS to query
m_arrMultiQI); // array of IID pointers to query
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -