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

📄 datasink20.cpp

📁 KepWare的OPC Client 示例.面向C
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// **************************************************************************
// datasink20.cpp
//
// Description:
//	Implements the IKDataSink20 class and IOPCDataCallback COM interface.
//	Groups in OPC Servers can use the IOPCDataCallback interface to advise us
//	of data change events.
//
//	OPC 2.0 requires that all member functions of the IOPCDataCallback
//	interface be implemented: OnDataChange, OnReadComplete, OnWriteComplete,
//	and OnCancelComplete.
//
//	The IOPCDataCallback interface is used by OPC version 2.0.  OPC version
//	1.0 uses the IAdviseSink interface instead.  If you know that your
//	server(s) will only be using OPC version 1.0, you don't really need this.
//
// 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 "datasink20.h"
#include "group.h"
#include "item.h"


// **************************************************************************
// IKDataSink20 ()
//
// Description:
//	Constructor.  Reference count is initialized to zero.
//
// Parameters:
//	none
//
// Returns:
//	none
// **************************************************************************
IKDataSink20::IKDataSink20 () : m_cnRef (0)
	{
	}

// **************************************************************************
// ~IKDataSink20 ()
//
// Description:
//	Destructor
//
// Parameters:
//	none
//
// Returns:
//	none
// **************************************************************************
IKDataSink20::~IKDataSink20 ()
	{
	}

// **************************************************************************
// AddRef ()
//
// Description:
//	This function is called to increment our reference count.  Caller should 
//	increment our reference count each time a new pointer to this interface
//	is created (except when obtained by a call to QueryInterface which will
//  bump the reference count on its behalf). 
//
//	This is one of the 3 member functions all COM interfaces must implement. 
//
// Parameters:
//	none
//
// Returns:
//	STDMETHODIMP_(ULONG) - Reference count resulting from this call.
// **************************************************************************
STDMETHODIMP_(ULONG) IKDataSink20::AddRef ()
	{
	// Increment the reference count then return value:
	return (++m_cnRef);
	}

// **************************************************************************
// Release ()
//
// Description:
//	This function is called to decrement our reference count.  Caller should
//	decrement our reference count just before each pointer to this interface 
//	is destroyed (goes out of scope).  Standard COM practice requires us to
//  self-delete once the refernce count returns to zero.
//
//	This is one of the 3 member functions all COM interfaces must implement.
//
// Parameters:
//	none
//
// Returns:
//	STDMETHODIMP_(ULONG) - Reference count resulting from this call.
// **************************************************************************
STDMETHODIMP_(ULONG) IKDataSink20::Release ()
	{
	// Decrement reference count and return immediately if not zero:
	if (--m_cnRef != 0)
		return (m_cnRef);

	// If we make it here, then the reference count is zero.  We are 
	// therefore obliged to delete ourselves:
	delete this;

	// Return our refence count, which is zero now:
	return (0);
	}

// **************************************************************************
// QueryInterface ()
//
// Description:
//	This function is called to obtain a pointer to one of the COM interfaces
//	objects of this class support (in this case only IAdviseSink and its base
//	class IUnknown).  As is standard COM practice, our reference count is 
//	incremented upon a successful query.  
//
//  This is one of the 3 member functions all COM interfaces must implement.	
//
// Parameters:
//	REFIID		riid			Requested interface type: IID_IUnknown,
//								  or IID_IAdviseSink.
//	LPVOID		*ppInterface	Pointer to requested interface.
//
// Returns:
//	STDMETHODIMP -
//		S_OK - Query successful, ppInterface set to requested pointer.
//		E_INVALIDARG - One of the arguments was invalid.
//		E_NOINTERFACE - Requested interface is not supported.
// **************************************************************************
STDMETHODIMP IKDataSink20::QueryInterface (REFIID iid, LPVOID *ppInterface)
	{
	// Validate ppInterface.  Return with "invalid argument" error code if invalid:
	if (ppInterface == NULL)
		return (E_INVALIDARG);

	// Standard COM practice requires that we invalidate output arguments
	// if an error is encountered.  Let's assume an error for now and invalidate
	// ppInterface.  We will reset it to a valid interface pointer later if we
	// determine requested ID is valid:
	*ppInterface = NULL;	

	// Reset ppInterface if requested interface type is valid:
	if (iid == IID_IUnknown)
		*ppInterface = (IUnknown *) this;
	else if (iid == IID_IOPCDataCallback)
		*ppInterface = (IOPCDataCallback *) this;
	else
		{
		// We have been asked for an interface we don't support.  Return 
		// immediately with "no interface" error code.  ppInterface should
		// still be NULL as required by COM.
		return (E_NOINTERFACE);
		}

	// If we made it here, then the query was successful and ppInterface
	// has been set to requested interface pointer.  Standard COM practice
	// requires us to increment our reference count now.
	AddRef ();

	// Return with "success" code:
	return (S_OK);
	}

// **************************************************************************
// OnDataChange ()
//
// Description:
//	This method is provided to handle notifications from an OPC Group for
//	exception based (unsolicited) data changes and refreshes.  Data for one
//	or possibly more active items in the group will be provided.
//
// Parameters:
//	DWORD		dwTransID			Zero for normal OnDataChange events, 
//                                    non-zero for Refreshes.
//	OPCHANDLE	hGroup				Client group handle.
//	HRESULT		hrMasterQuality		S_OK if all qualities are GOOD, otherwise S_FALSE.
//	HRESULT		hrMasterError		S_OK if all errors are S_OK, otherwise S_FALSE.
//	DWORD		dwCount				Number of items in the lists that follow.
//	OPCHANDLE	*phClientItems		Item client handles.
//	VARIANT		*pvValues			Item data.
//	WORD		*pwQualities		Item qualities.
//	FILETIME	*pftTimeStamps		Item timestamps.
//	HRESULT		*pErrors			Item errors.
//
// Returns:
//	STDMETHODIMP - 
//		S_OK - Processing of advisement successful.
//		E_INVALIDARG - One of the arguments was invalid.
// **************************************************************************
STDMETHODIMP IKDataSink20::OnDataChange (DWORD dwTransID,
						OPCHANDLE hGroup,
						HRESULT hrMasterQuality,
						HRESULT hrMasterError,
						DWORD dwCount,
						OPCHANDLE *phClientItems,
						VARIANT *pvValues,
						WORD *pwQualities,
						FILETIME *pftTimeStamps,
						HRESULT *pErrors)
	{
	CKGroup *pGroup = NULL;
	CKItem *pItem = NULL;

	// Initialize a bad item handle counter (used for debugging only):
	DWORD cdwBadItemHandles = 0;

	// Validate arguments.  Return with "invalid argument" error code 
	// if any are invalid:
	if (hGroup					== NULL	||
		dwCount					== 0	||
		phClientItems			== NULL	||
		pvValues				== NULL	||
		pwQualities				== NULL	||
		pftTimeStamps			== NULL	||
		pErrors					== NULL)
		return (E_INVALIDARG);

	// The group argument gives us a pointer to the destination CKGroup:
	pGroup = (CKGroup *) hGroup;

	// Post a "read complete" message for refresh transactions (which will 
	// have a non-zero transaction ID).  No need to load up event log with 
	// "read complete" messages for unsolicited data updates, which could be
	// coming in many times per second.
	if (dwTransID != 0)
		{
		LogMsg (IDS_ASYNC20_READXACT_COMPLETE, dwTransID, dwCount,
				pGroup->GetName (), hrMasterError);
		}

	// Loop over items:
	for (DWORD dwItem = 0; dwItem < dwCount; dwItem++)
		{
		// The client item handles give us pointers to the destination
		// CKItem objects:
		pItem = (CKItem *) phClientItems [dwItem];

		// Wrap use of pItem in exception handler in case pointer is bad:
		try
			{
			// Update the item's value, quality, and timestamp:

⌨️ 快捷键说明

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