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

📄 server.cpp

📁 KepWare的OPC Client 示例.面向C
💻 CPP
📖 第 1 页 / 共 4 页
字号:
// **************************************************************************
// server.cpp
//
// Description:
//	Implements the CKServer class.  An object of this class is associated with
//	with each OPC Server we may connect to.
//
// DISCLAIMER:
//	This programming example is provided "AS IS".  As such Kepware, Inc.
//	makes no claims to the worthiness of the code and does not warranty
//	the code to be error free.  It is provided freely and can be used in
//	your own projects.  If you do find this code useful, place a little
//	marketing plug for Kepware in your code.  While we would love to help
//	every one who is trying to write a great OPC client application, the 
//	uniqueness of every project and the limited number of hours in a day 
//	simply prevents us from doing so.  If you really find yourself in a
//	bind, please contact Kepware's technical support.  We will not be able
//	to assist you with server related problems unless you are using KepServer
//	or KepServerEx.
// **************************************************************************


#include "stdafx.h"
#include "opctestclient.h"
#include "server.h"
#include "group.h"
#include "item.h"
#include "shutdownsink.h"
#include "mainwnd.h"

// Versions for serializing:
#define VERSION_1					1			// serialized verions
#define CURRENT_VERSION				VERSION_1	// current version for saving

// m_arrMultiQI indices:
#define MQI_IOPCSERVER		0
#define MQI_IOPCCOMMON		1
#define MQI_IOPCCONNPT		2
#define MQI_IOPCITEMPROP	3
#define MQI_IOPCBROWSE		4
#define MQI_IOPCPUBLIC		5
#define MQI_IOPCPERSIST		6

// Satisfy OPCENUM requirements
static const CLSID CLSID_OPCServerList = 
{ 0x13486D51, 0x4821, 0x11D2, { 0xA4, 0x94, 0x3C, 0xB3, 0x06, 0xC1, 0x00, 0x00 } };

/////////////////////////////////////////////////////////////////////////////
// CKServer construction/destruction
/////////////////////////////////////////////////////////////////////////////

// **************************************************************************
// CKServer ()
//
// Description:
//	Default constructor.
//
// Parameters:
//  none
//
// Returns:
//  none
// **************************************************************************
CKServer::CKServer ()
	{
	// Initialize members:
	m_strProgID = cApp.GetDefConnectProgID ();
	m_strRemoteMachine.Empty ();

	ZeroMemory (&m_bfFlags, sizeof (m_bfFlags));

	m_pPrev = NULL;
	m_pNext = NULL;

	m_hTreeItem = NULL;
	
	m_pGroupHead = NULL;
	m_cdwGroups = 0;

	// Fill our multiple query interface structure with all of the
	// interfaces we can possible request at the server level:
	for (int i = 0; i < sizeof (m_arrMultiQI) / sizeof (MULTI_QI); i++)
		{
		m_arrMultiQI [i].pItf = NULL;
		m_arrMultiQI [i].hr = 0;
		}
	
	// Interface pointers we will query and maintain:
	m_pIServer				= NULL;
	m_pICommon				= NULL;
	m_pIConnPtContainer		= NULL;
	m_pIItemProps			= NULL;
	m_pIBrowse				= NULL;
	m_pIPublicGroups		= NULL;
	m_pIPersistFile			= NULL;	

	m_pIShutdownSink		= NULL;
	m_dwCookieShutdownSink	= 0;
	
	m_bConnected = false;
	}

// **************************************************************************
// CKServer
//
// Description:
//	Constructor for when OPC Server's prog ID and the machine name it will be
//	running on are known.
//
// Parameters:
//  CString		&strProgID			Prog ID of server.
//	CString		&strRemoteMachine	Name of remote machine.
//
// Returns:
//  none
// **************************************************************************
CKServer::CKServer (CString &strProgID, CString &strRemoteMachine)
	{
	ASSERT (!strProgID.IsEmpty ());

	// Initialize members:
	m_strProgID = strProgID;
	m_strRemoteMachine = strRemoteMachine;

	ZeroMemory (&m_bfFlags, sizeof (m_bfFlags));

	m_pPrev = NULL;
	m_pNext = NULL;

	m_hTreeItem = NULL;
	
	m_pGroupHead = NULL;
	m_cdwGroups = 0;

	// Fill our multiple query interface structure with all of the
	// interfaces we can possible request at the server level:
	for (int i = 0; i < sizeof (m_arrMultiQI) / sizeof (MULTI_QI); i++)
		{
		m_arrMultiQI [i].pItf = NULL;
		m_arrMultiQI [i].hr = 0;
		}
	
	// Interface pointer we will query and maintain:
	m_pIServer				= NULL;
	m_pICommon				= NULL;
	m_pIConnPtContainer		= NULL;
	m_pIItemProps			= NULL;
	m_pIBrowse				= NULL;
	m_pIPublicGroups		= NULL;
	m_pIPersistFile			= NULL;	

	m_pIShutdownSink		= NULL;
	m_dwCookieShutdownSink	= 0;
	
	m_bConnected = false;
	}

// **************************************************************************
// ~CKServer ()
//
// Description:
//	Destructor.
//
// Parameters:
//  none
//
// Returns:
//  none
// **************************************************************************
CKServer::~CKServer ()
	{
	// Remove all groups:
	RemoveAllGroups ();

	// Disconnect from the OPC Sserver we are connected to:
	Disconnect ();

	// Assert that all interfaces and groups have been properly released:
	ASSERT (m_cdwGroups == 0);
	ASSERT (m_pIServer == NULL);
	ASSERT (m_pICommon == NULL);
	ASSERT (m_pIConnPtContainer == NULL);
	ASSERT (m_pIItemProps == NULL);
	ASSERT (m_pIBrowse == NULL);
	ASSERT (m_pIPublicGroups == NULL);
	ASSERT (m_pIPersistFile == NULL);
	ASSERT (m_pIShutdownSink == NULL);
	ASSERT (m_dwCookieShutdownSink == 0);
	}


/////////////////////////////////////////////////////////////////////////////
// CKServer group management
/////////////////////////////////////////////////////////////////////////////

// **************************************************************************
// AddGroup ()
//
// Description:
//	Called to add an OPC Group.  A CKGroup will be added to this object if
//	needed and a request to add a corresponding OPC Group to the OPC Server
//	will be made.
//
// Parameters:
//  CKGroup		*pGroup			Pointer to group object to add.
//	bool		bLoadingProject	Set to true if call is made during project 
//								  load so group can be added to this object's
//								  group list.  Otherwise we will assume group
//								  already exists in list, and only needs to
//								  added to OPC Server.
//
// Returns:
//  void
// **************************************************************************
void CKServer::AddGroup (CKGroup *pGroup, bool bLoadingProject /*= false */)
	{
	ASSERT (pGroup != NULL);

	// If the group is new add it to our list:
	if (!bLoadingProject)
		{
		// 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;

		// Don't forget to bump up the group count:
		++m_cdwGroups;
		}

	// If we are connected to OPC Server, issue a request to add this group:
	if (m_bConnected)
		{
		// Initialize arguments for add group request:
		HRESULT hr				= E_FAIL;
		WCHAR *pszName			= NULL;
		long lBias				= pGroup->GetBias ();
		float fDeadband			= pGroup->GetDeadband ();
		LPCTSTR lpszName		= pGroup->GetName ();
		DWORD dwRevUpdateRate	= 0;
		OPCHANDLE hServer		= NULL;
		IUnknown *pUnknown		= NULL;

		// All strings transmitted by COM must be in wide character (Unicode) format.
		// Declare a buffer to contain name string in wide character format.
		WCHAR wchBuffer	[DEFBUFFSIZE];

		// Convert the string format:
		if (lpszName != NULL)
			{
#ifdef _UNICODE
			// String is already in Unicode format, so simply copy into buffer:
			lstrcpyn (wchBuffer, lpszName, sizeof (wchBuffer) / sizeof (WCHAR));
#else
			// String is not in Unicode format, so convert and place result into buffer:
			if (!MultiByteToWideChar (CP_ACP, 0, lpszName, -1, wchBuffer, DEFBUFFSIZE))
				{
				ASSERT (FALSE);
				return;
				}
#endif

			// Reassign name pointer to buffer:
			pszName = wchBuffer;
			}
		
		// Issue add OPC Group request using IOPCServer interface.  Pointer to 
		// the IOPCServer interface, m_pIServer, should have been set in Connect().
		hr = m_pIServer->AddGroup (
			pszName,					// [in] group name
			pGroup->IsActive (),		// [in] active state
			pGroup->GetUpdateRate (),	// [in] requested update rate
			(OPCHANDLE) pGroup,			// [in] our handle to this group
			&lBias,						// [in] time bias
			&fDeadband,					// [in] percent deadband
			pGroup->GetLanguageID (),	// [in] requested language ID
			&hServer,					// [out] server handle to this group
			&dwRevUpdateRate,			// [out] revised update rate
			IID_IUnknown,				// [in] request an IUknown pointer
			&pUnknown);

		// OPC Group was successfully added:
		if (SUCCEEDED (hr))
			{
			// Log success:
			LogMsg (IDS_GROUP_ADD_SUCCESS, pGroup->GetName (), GetProgID ());

			// Since OPC Group was successfully added, we can go ahead an initialize
			// the associated CKGroup object.

			// We can now consider group valid:
			pGroup->SetValid (TRUE);

			// We should have gotten a valid pointer to the OPC Groups's IUnknown interface.
			// Set some things that only make sence if we have a vaild IUnknown pointer:
			if (pUnknown)
				{
				// Set the OPC Server's handle for this group:
				pGroup->SetServerHandle (hServer);

				// Reset update rate if OPC Server does not support requested rate:
				if (pGroup->GetUpdateRate () != dwRevUpdateRate)
					pGroup->SetUpdateRate (dwRevUpdateRate);

				// Initialize the CKGroup object, which will include getting necessary
				// interface pointers from IUnknown:
				pGroup->Initialize (pUnknown);

				// We can release the IUnknown pointer since initialized group
				// should have gotten the interface pointers it needs from it.
				pUnknown->Release ();
				}
			else
				{
				TRACE (_T("OTC: Warning added group %s to OPC server, but IUnknown is invalid.\r\n"),
					pGroup->GetName ());
				}
			}

		// OPC Group was not successfully added:
		else
			{
			// Log message that says add OPC Group request failed:
			LogMsg (IDS_GROUP_ADD_FAILURE, pGroup->GetName (), GetProgID (), hr);
			}
		}

	// No connection:
	else
		{
		// Log message that says we can't add the OPC Group because we are not
		// connected to OPC Server:
		LogMsg (IDS_SERVER_ADD_GROUP_FAILED_NOCONNECTION, pGroup->GetName (), GetProgID ());
		}
	}

// **************************************************************************
// AddClonedGroup ()
//
// Description:
//	Add cloned group to list.  
//
//	This is called from CKGroup::Clone (), which takes care of instantiating
//  the new CKGroup object and adding its associated OPC Group to the OPC
//  Server.  All that's left to do here is add the clone to the group list. 
//
// Parameters:
//  CKGroup		*pClone		Pointer to cloned group.
//
// Returns:
//  void
// **************************************************************************
void CKServer::AddClonedGroup (CKGroup *pClone)
	{
	// New groups are added to the head of the linked list.

	// That means the clone's "next" group is old head of list,
	pClone->SetNext (m_pGroupHead);

	// and the clone is the old head of list's "previous" group,
	if (m_pGroupHead)	
		m_pGroupHead->SetPrev (pClone);
		
	// and that clone is now the new "head" of list.
	m_pGroupHead = pClone;

	// Don't forget to bump up the group count:
	++m_cdwGroups;
	}

// **************************************************************************
// RemoveGroup ()
//
// Description:
//	Remove an OPC Group from OPC server, and delete associated CKGroup object
//	if asked.
//
// Parameters:
//  CKGroup		*pGroup			Pointer to CKGroup associated with OPC Group
//								  to remove.
//	bool		bDelete			Delete CKGroup object after removing
//								  associated OPC Group. true by default.
//
// Returns:
//  void
// **************************************************************************
void CKServer::RemoveGroup (CKGroup *pGroup, bool bDelete /* = true */)
	{
	ASSERT (pGroup != NULL);

	HRESULT hr;

	// Uninitialize group with OPC server.  This means all interfaces it
	// is using are released.  It is good practice to do this BEFORE
	// issuing a remove group request.  Pass the bDelete value so the 
	// group knows to delete its items if any.
	pGroup->Uninitialize (bDelete);

	// remove the group from the OPC server
	if (pGroup->IsValid ())
		{
		ASSERT (m_pIServer != NULL);

		// Issue remove OPC Group request using IOPCServer interface.  Pointer to 
		// the IOPCServer interface, m_pIServer, should have been set in Connect().
		hr = m_pIServer->RemoveGroup (
			pGroup->GetServerHandle (),		// server handle for this group.
			pGroup->IsForceDeletion ());	// force a delete if this client has not released the group properly.

		// Log success or failure:
		if (SUCCEEDED (hr))
			LogMsg (IDS_GROUP_REMOVE_SUCCESS, pGroup->GetName (), GetProgID ());
		else
			LogMsg (IDS_GROUP_REMOVE_FAILURE, pGroup->GetName (), GetProgID (), hr);
		}

	// Delete the group if asked:
	if (bDelete)
		{
		// We need to remove the group from the linked list before we delete it.

		// To remove a link, we must first get pointers to the adjacent links:
		CKGroup *pPrev = pGroup->GetPrev ();
		CKGroup *pNext = pGroup->GetNext ();
		
		// If there is a "previous" link, then its "next" is removed link's "next",
		if (pPrev)
			pPrev->SetNext (pNext);

		// and if there is a "next" link, then its "previous" is removed link's "previous",
		if (pNext)
			pNext->SetPrev (pPrev);

		// and if removed link was the "head", then the new head is removed link's "next".

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -