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

📄 libopc.cpp

📁 自动化领域的软件标准通讯接口OPC的封装
💻 CPP
📖 第 1 页 / 共 2 页
字号:

#include "stdAfx.h"
#include "LibApp.h"
#include "LibOPC.h"
#include "opcda_i.c"
#include <comdef.h>

const int _OPC_DUPLICATE_GROUP_NAME		= -101 ;
const int _OPC_INVALID_OBJECT			= -102 ;
const int _OPC_TOO_MANY_ITEMS			= -103 ;
const int _OPC_INVALID_GROUP_NAME		= -104 ;
const int _OPC_SERVER_NOT_CONNECTED		= -105 ;

const int _OPC_MAX_HANDLE				= 2000 ;


///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
CAppServer::CAppServer() :
	m_nGroupNo(-1),
	m_nTotalGroups(0),
	m_GroupHandle (0)
{
	for (int i=0; i<_OPC_MAX_GROUP; i++)
	{
		GroupNumber[i].m_szGrpName[0] = L'\0' ;
		GroupNumber[i].m_GroupHandle = 0 ;
		GroupNumber[i].m_NoOfItems = 0 ;
		GroupNumber[i].m_nGroupNo = -1 ;
	}
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
CAppServer::~CAppServer()
{
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
CAppServer::CAppServer(wchar_t* svrName, wchar_t* svrType) :
	m_nGroupNo(-1),
	m_nTotalGroups(0),
	m_GroupHandle (0)
{
	wcscpy (m_wstrServerName, svrName) ;
	wcscpy (m_wstrServerType, svrType) ;
	for (int i=0; i<_OPC_MAX_GROUP; i++)
	{
		GroupNumber[i].m_szGrpName[0] = L'\0' ;
		GroupNumber[i].m_GroupHandle = 0 ;
		GroupNumber[i].m_NoOfItems = 0 ;
		GroupNumber[i].m_nGroupNo = -1 ;
	}
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
CAppServer::CAppServer (const CAppServer &rhs) :
	m_nGroupNo (rhs.m_nGroupNo),
	m_nTotalGroups(rhs.m_nTotalGroups),
	m_GroupHandle (rhs.m_GroupHandle),
	m_pIOPCServer (rhs.m_pIOPCServer),
	m_pIOPCSyncIO (rhs.m_pIOPCSyncIO)
{
	wcscpy (m_wstrServerName, rhs.m_wstrServerName) ;
	wcscpy (m_wstrServerType, rhs.m_wstrServerType) ;
	for (int i=0; i<_OPC_MAX_GROUP; i++)
	{
		GroupNumber[i] = rhs.GroupNumber[i] ;
		m_pIOPCGroupStateMgt[i] = rhs.m_pIOPCGroupStateMgt[i] ;
	}
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
CAppServer& CAppServer::operator=(const CAppServer &rhs)
{
	m_nGroupNo = rhs.m_nGroupNo ;
	m_nTotalGroups = rhs.m_nTotalGroups ;
	m_GroupHandle = rhs.m_GroupHandle ;
	m_pIOPCServer = rhs.m_pIOPCServer ;
	m_pIOPCSyncIO = rhs.m_pIOPCSyncIO ;
	wcscpy(this->m_wstrServerName, rhs.m_wstrServerName) ;
	wcscpy(this->m_wstrServerType, rhs.m_wstrServerType) ;
	for (int i=0; i<_OPC_MAX_GROUP; i++)
	{
		GroupNumber[i] = rhs.GroupNumber[i] ;
		m_pIOPCGroupStateMgt[i] = rhs.m_pIOPCGroupStateMgt[i] ;
	}

	return *this ;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
HRESULT CAppServer::OPCConnect(wchar_t* svrName, wchar_t* svrType)
{
	CLSID clsid ;
	COSERVERINFO csvrinfo;
	MULTI_QI queryInterface;
	LPUNKNOWN pUnkn = NULL;
	HRESULT hr ;

	wcscpy (m_wstrServerName, svrName) ;
	wcscpy (m_wstrServerType, svrType) ;

	// Get the Class ID from the Program ID
	// Take note that the server name and type must be wide-character
	hr = CLSIDFromProgID(m_wstrServerType, &clsid );

	if ( FAILED (hr))
		return hr ;

	// Assign GUID of IOPCServer Interface to the MULTI_QI structure
	queryInterface.pIID = &IID_IOPCServer ;  
	queryInterface.pItf = NULL ;
	queryInterface.hr = 0 ;

	memset(&csvrinfo, 0, sizeof(COSERVERINFO));
	csvrinfo.pAuthInfo = NULL ;
	// If the server name is blank, assume the server is
	// the Local Server, and set it to NULL
	if (!wcslen(m_wstrServerName))
		csvrinfo.pwszName = NULL ;
	else
		csvrinfo.pwszName = m_wstrServerName ;

	// Create an instance and retrieve the IOPCServer Interface
	hr = ::CoCreateInstanceEx(clsid, NULL, CLSCTX_SERVER, &csvrinfo, 1, &queryInterface);
	m_pIOPCServer = queryInterface.pItf ;

	if( FAILED(hr) || m_pIOPCServer == NULL)
		return hr ;

	queryInterface.pItf->Release() ;
	return hr ;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
HRESULT CAppServer::OPCConnect()
{
	CLSID clsid ;
	COSERVERINFO csvrinfo;
	MULTI_QI queryInterface;
	LPUNKNOWN pUnkn = NULL;
	HRESULT hr ;

	// Get the Class ID from the Program ID
	// Take note that the server name and type must be wide-character
	hr = CLSIDFromProgID(m_wstrServerType, &clsid );

	if ( FAILED (hr))
		return hr ;

	// Assign GUID of IOPCServer Interface to the MULTI_QI structure
	queryInterface.pIID = &IID_IOPCServer ;
	queryInterface.pItf = NULL ;
	queryInterface.hr = 0 ;

	memset(&csvrinfo, 0, sizeof(COSERVERINFO));
	csvrinfo.pAuthInfo = NULL ;

	// If the server name is blank, assume the server is
	// the Local Server, and set it to NULL
	if (!wcslen(m_wstrServerName))
		csvrinfo.pwszName = NULL ;
	else
		csvrinfo.pwszName = m_wstrServerName ;

	// Create an instance and retrieve the IOPCServer Interface
	hr = ::CoCreateInstanceEx(clsid, NULL, CLSCTX_SERVER, &csvrinfo, 1, &queryInterface);
	m_pIOPCServer = queryInterface.pItf ;

	if( FAILED(hr) || m_pIOPCServer == NULL)
		return hr ;

	queryInterface.pItf->Release() ;
	return hr ;
}

///////////////////////////////////////////////////////////////////////////
// This Method adds a group to the OPC Server
// Note that when a group is added, the group becomes the
// current default group. This means that all subsequent operation
// i.e. addition of tags, reading or writing of tags will use this group.
// If operation on a different group is to be carried out, then the group
// must be changed first by using the method, OPCChangeGroup().
///////////////////////////////////////////////////////////////////////////
HRESULT CAppServer::OPCAddGroup(LPWSTR szGrpName)
{
	HRESULT hr ;
	bool bActive = TRUE ;
	OPCHANDLE hClientGroupHandle = 1000 ;
	DWORD dwLCID = 0 ;
	DWORD dwRtnUpdateRate ;
	long *pTimeBias = NULL ;
	DWORD dwReqUpdateRate = 1000 ;
	float pPercentDeadband = 0.0;
	CGroup GrpNum ;

//	_wcsupr(szGrpName) ;  // Convert all Uppercase for easy comparison
	if (AddGroupName (szGrpName, GrpNum))
		return _OPC_DUPLICATE_GROUP_NAME ;

	m_nGroupNo = GrpNum.m_nGroupNo ;

	// Add a group
	hr = m_pIOPCServer->AddGroup( szGrpName, TRUE, 1000, //szGrpName, TRUE, 1000,
							1324, NULL, &pPercentDeadband, //hClientGroupHandle, NULL, NULL, 
							dwLCID, &m_GroupHandle, &dwRtnUpdateRate,
							IID_IOPCGroupStateMgt,
							reinterpret_cast<IUnknown**> (&m_pIOPCGroupStateMgt[m_nGroupNo]));

	if (FAILED (hr))
	{
		GroupNumber[m_nGroupNo].m_szGrpName[0] = L'\0' ;
		m_pIOPCGroupStateMgt[m_nGroupNo].Release() ;
		return hr ;
	}

	GroupNumber[m_nGroupNo].m_GroupHandle = m_GroupHandle ;
	m_nTotalGroups++ ;

	return hr ;

}

///////////////////////////////////////////////////////////////////////////
// This Method adds tags to the current group. If tags are to be added
// to a different group, then the group must be changed first by using
// OPCChangeGroup() method.
// ItemIDs is an array of tagnames.
// ClientHandles is an array of arbitarily assigned integers by the caller.
// ServerHandles is an array corresponding to the ClientHandles array returned 
// by OPC Server.Use the ServerHandles for all reading or writing of items to
//  the OPC Server. The OPC Server knows only the ServerHandles.
///////////////////////////////////////////////////////////////////////////
HRESULT CAppServer::OPCAddTags (wchar_t* ItemIDs[], DWORD NoOfItems, OPCHANDLE ClientHandles[],
									OPCHANDLE ServerHandles[], CErrors* pErr, int &nErr)
{
	HRESULT hr ;
	DWORD index ;
	OPCITEMDEF* idef ;
	OPCITEMRESULT* pResults ;
	HRESULT* pErrors ;

	// Assign the variable pItemMgt of type IOPCItemMgt Interface using the 
	// smart pointer, CComQIPtr. CComQIPtr will add and release references automatically
	CComQIPtr <IOPCItemMgt, &IID_IOPCItemMgt> pItemMgt (m_pIOPCGroupStateMgt[m_nGroupNo]) ;

	if (!m_pIOPCServer || !m_pIOPCGroupStateMgt[m_nGroupNo] || NoOfItems <= 0)
		return _OPC_INVALID_OBJECT ;

	if (NoOfItems > _OPC_MAX_HANDLE)
		return _OPC_TOO_MANY_ITEMS ;

//	for (DWORD idx=0; idx<NoOfItems; idx++)
//		_wcsupr(ItemIDs[idx]) ;  // OPC requuires items to be Uppercase. May not be necessary now.

	GroupNumber[m_nGroupNo].m_NoOfItems += NoOfItems ;

	// create a new OPC Item Definition pointer
	idef = new OPCITEMDEF [NoOfItems] ;

	for ( index=0; index<NoOfItems ; index++ ) 
	{
		idef[index].szItemID = (LPTSTR)(LPCTSTR)ItemIDs[index];
		idef[index].bActive = TRUE;
		idef[index].dwBlobSize = 0;
		idef[index].pBlob = NULL;
		idef[index].szAccessPath = NULL;
		idef[index].hClient = ClientHandles[index] ;
		idef[index].vtRequestedDataType = VT_EMPTY;
	}

	// Add items using the IOPCItemMgt pointer
	hr = pItemMgt->AddItems (NoOfItems, idef, &pResults, &pErrors) ;
	delete []idef;

	if (FAILED(hr))
		return hr ;

	DWORD setNum = 0 ;
	nErr = 0 ;
	for (index=0; index<NoOfItems; index++)
	{
		if ( SUCCEEDED(pErrors[index]) ) 
			ServerHandles[index] = pResults[index].hServer ;
		else
			nErr++ ;

		pErr[index].pErrors = pErrors[index] ;
	}

	CoTaskMemFree( pResults );
	CoTaskMemFree( pErrors );

	return hr ;
}

///////////////////////////////////////////////////////////////////////////
// This Method Read Tags.
// pValues is a structure of type CItem. See CItem in the header file
// ServerHandles is the array originally used in the OPCAddTags().
///////////////////////////////////////////////////////////////////////////
HRESULT CAppServer::OPCReadTags (CItem* pValues, DWORD NoOfItems, OPCHANDLE ServerHandles[],int &nErr)
{
	// Test to see if the Interface is still connected to the server
	if (!CoIsHandlerConnected (m_pIOPCGroupStateMgt[m_nGroupNo]))
	{
		m_pIOPCGroupStateMgt[m_nGroupNo].Release() ;
	}

	OPCITEMSTATE* pItemState;
	HRESULT hr, *pErrors;

	// Assign the variable opcSyncIO of type IOPCSyncIO Interface using the 
	// smart pointer, CComQIPtr. CComQIPtr will add and release references automatically
	CComQIPtr<IOPCSyncIO, &IID_IOPCSyncIO> opcSyncIO (m_pIOPCGroupStateMgt[m_nGroupNo]) ;

	if (NoOfItems <= 0 || NoOfItems > _OPC_MAX_HANDLE)
		return _OPC_TOO_MANY_ITEMS ;

//	for (DWORD idx=0; idx<NoOfItems; idx++)
//		_wcsupr(pValues[idx].cName) ;

	// Read the items using the IOPCSyncIO Interface pointer.
	hr = opcSyncIO->Read(OPC_DS_CACHE, NoOfItems, ServerHandles, &pItemState, &pErrors);

	if( SUCCEEDED(hr) )
	{
		nErr = 0 ;
		for(DWORD index=0; index < NoOfItems; index++) 
		{
			if ( FAILED(pErrors[index]) ) 
				nErr++ ;

			pValues[index].quality = pItemState[index].wQuality ;
			pValues[index].timestamp = pItemState[index].ftTimeStamp ;
			pValues[index].hClient = pItemState[index].hClient ;
			pValues[index].type = pItemState[index].vDataValue.vt ;
			pValues[index].value.vt = pItemState[index].vDataValue.vt ;
			pValues[index].nResult = pErrors[index] ;
			ReadDataValues(pValues, pItemState, index) ;
		}
		CoTaskMemFree( pItemState );
		CoTaskMemFree( pErrors );
	}
	else 
	{
		CoTaskMemFree( pItemState );
		CoTaskMemFree( pErrors );
	}
	// if hr = S_OK, all the data is guarantee to be good.
	// if hr = S_FALSE, there are good and bad data.

⌨️ 快捷键说明

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