⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 server.cpp

📁 KepWare的OPC Client 示例.面向C
💻 CPP
📖 第 1 页 / 共 4 页
字号:
						// 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 + -