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

📄 infoserver.cpp

📁 此文件为VC++开发环境下的OPC client trend 源代码
💻 CPP
字号:
/////////////////////////////////////////////////////////////////////////////
//
//  OPC Trend VC++ Client:	InfoServer.CPP
//							(Source File)
//
/////////////////////////////////////////////////////////////////////////////
//
//          Author: Raphael Imhof
//    Initial Date: 11/04/98
//       $Workfile: InfoServer.cpp $
//       $Revision: 1 $
//           $Date: 7/27/99 5:24p $
//   Target System: Microsoft Windows NT 4.0
//     Environment: Visual C++ 5.0 / OPC DataAccess 1.0 / 2.0
//         Remarks: 
//
/////////////////////////////////////////////////////////////////////////////
//
//     Description: implementation of the CInfoServer class.
//					Encapsulation of OPC server related methods.
//					
//
/////////////////////////////////////////////////////////////////////////////
//
//  History of Changes     (Please remove very old comments and blank lines!)
//            $Log: /IDK/OPCServer/clients/VC++/Trend/InfoServer.cpp $
// 
// 1     7/27/99 5:24p Imhof
// 
// 1     7/27/99 5:19p Imhof
// 
// 7     2/08/99 8:02p Imhof
// Removed possible memory leak after a server shutdown.
// 
// 6     1/15/99 7:04p Imhof
// Updated legal notice.
// 
// 5     12/15/98 10:30a Imhof
// Modifications for OPC 2.0
// 
// 4     11/06/98 5:53p Imhof
// Added header, comment and made some small code changes.
// 
// 
//  $Nokeywords:$ (To avoid useless search while checking in.)
/////////////////////////////////////////////////////////////////////////////
//  Copyright (C) 1998, Siemens Building Technologies, Inc. Landis Division
//
// SIEMENS BUILDING TECHNOLOGIES, INC. IS PROVIDING THE FOLLOWING
// EXAMPLES OF CODE AS SAMPLE ONLY.
//
// SIEMENS BUILDING TECHNOLOGIES, INC.  MAKES NO REPRESENTATIONS
// OR WARRANTIES OF ANY KIND  WITH RESPECT TO THE VALIDTY OF THE 
// CODES   OR   DESIRED   RESULTS   AND   DISCLAIMS   ALL   SUCH 
// REPRESENTATIONS   AND   WARRANTIES,  INCLUDING  FOR  EXAMPLE, 
// WARRANTIES  OF  MERCHANTABILITY  AND FITNESS FOR A PARTICULAR 
// PURPOSE.    SIEMENS  BUILIDNG  TECHNOLOGIES,  INC.  DOES  NOT 
// REPRESENT  OR  WARRANT  THAT  THE  FOLLOWING CODE SAMPLES ARE 
// ACCURATE, VALID, COMPLETE OR CURRENT.
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "InfoServer.h"
#include "resource.h"
#include "trend.h"
#include "connectdlg.h"
/*
	no async trend read support
#include "IDataObject.h"
*/

#include <opcda_i.c> //for linker

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

CComModule _Module;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CInfoServer::CInfoServer()
{
	m_fOPCVersion = OPC_VERSION_20; //deafault: OPC 2.0	
	/*
	no async trend read support

	m_pAdviseSink = new CIAdviseSink;   // create the advise sink for notifications
	m_pAdviseSink->AddRef();
	*/

	m_pShutDownConnectionPoint = new CComObject<COPCShutDownRequest>;
	m_pShutDownConnectionPoint->AddRef();

	m_bConnected = FALSE;

	memset(&m_clsidOPCServer,0,sizeof(m_clsidOPCServer));
}

CInfoServer::~CInfoServer()
{	
	/* should be already done => size = 0 !
	int size = m_Groups.GetSize();
	CGroup* pGroup = NULL;
	for (int g = 0; g < size; g++)
	{
		pGroup = m_Groups[0];
		RemoveGroup(&pGroup);
	}
	*/

	/*
	no async trend read support
	m_pAdviseSink->Release(); //if not already done (this deletes the advise object!)
	*/

	m_pShutDownConnectionPoint->Release();

}

BOOL CInfoServer::ChooseServer()
{
	CConnectDlg		dlg;

	if(GetOPCVersion() < 2.0)
		dlg.m_catid = CATID_OPCDAServer10;
	else
		dlg.m_catid = CATID_OPCDAServer20;

	if(dlg.DoModal() != IDOK)
		return FALSE;
	
	if(IsConnected()) Disconnect();

	SetOPCServer(dlg.m_sOPCServer);
	SetOPCServerComputer(dlg.m_sOPCServerComputer);
	SetOPCServerCLSID(dlg.m_clsidServer);

	return TRUE;
}

BOOL CInfoServer::Connect()
{
	USES_CONVERSION;

	LPUNKNOWN	pUnkn = NULL;
	HRESULT		hr = S_OK;
	
	CWaitCursor wait;


	/* old OPC 1.0 way to retrieve the CLSID (note: new method covers OPC 1.0 servers as well)
	HKEY					hCLSID;
	HKEY					hkRoot = HKEY_CLASSES_ROOT;
	const int				MAX_CLSID_KEY_LEN = 256;
	LONG					clsid_size = MAX_CLSID_KEY_LEN;
	TCHAR					clsidString[MAX_CLSID_KEY_LEN];
	CLSID					clsid;

	if(!m_sOPCServerComputer.IsEmpty())
	{
		DWORD dwR = RegOpenKey(hkRoot, (LPTSTR)(LPCTSTR)m_sOPCServer, &hCLSID );
		if( dwR != ERROR_SUCCESS )
		{		
			DWORD dwR = RegConnectRegistry ((LPTSTR)(LPCTSTR)m_sOPCServerComputer, HKEY_CLASSES_ROOT, &hkRoot);
			if( dwR != ERROR_SUCCESS )
				return FALSE;
		}
	}

	DWORD dwR = RegOpenKey(hkRoot, (LPTSTR)(LPCTSTR)m_sOPCServer, &hCLSID );
	if( dwR != ERROR_SUCCESS )
		return FALSE;

	dwR = RegQueryValue(hCLSID, _T("CLSID"), clsidString, &clsid_size );
	if( dwR != ERROR_SUCCESS )
		return FALSE;

	hr = CLSIDFromString( T2OLE(clsidString), &clsid );
	if( FAILED(hr))
	{
		((CTrendApp*)AfxGetApp())->DisplayText(_T("CLSIDFromString()"), hr);
		return FALSE;
	}
	*/

	// Create a running object from that class ID
	// (CLSCTX_ALL will allow in-proc, local and remote)
	if(m_sOPCServerComputer.IsEmpty() )
	{
		hr = CoCreateInstance(GetOPCServerCLSID(), NULL, CLSCTX_ALL, IID_IUnknown, (LPVOID *)&pUnkn);
		if( FAILED(hr) || pUnkn == NULL)
		{
			CString sMsg;
			sMsg.Format( IDS_CONNECT_OPC_SERVER_ERROR, m_sOPCServer );
			sMsg += _T("\n CoCreateInstance()");
			
			((CTrendApp*)AfxGetApp())->DisplayText(sMsg, hr);
	
			return FALSE;
		}
	}
	else
	{
		COSERVERINFO	si;
		MULTI_QI		qi;

		si.dwReserved1 = 0;
		si.pwszName = T2OLE(m_sOPCServerComputer.GetBuffer(0));
		si.pAuthInfo = NULL;
		si.dwReserved2 = 0;

		qi.pIID = &IID_IOPCServer;
		qi.pItf = NULL;
		qi.hr = 0;

		hr = CoCreateInstanceEx(GetOPCServerCLSID(), NULL, CLSCTX_ALL, &si, 1, &qi);
		if (FAILED(hr))
		{
			((CTrendApp*)AfxGetApp())->DisplayText(_T("CoCreateInstanceEx()"), hr);
			return FALSE;
		}
		if (FAILED(qi.hr))
		{
			((CTrendApp*)AfxGetApp())->DisplayText(_T("Failed to connect to server"), qi.hr);
			return FALSE;
		}
		pUnkn = qi.pItf;
	}

	// Get the IOPCServer interface.
	m_pUnkn = pUnkn;
	//m_pUnkn->AddRef();
	pUnkn->Release();  // Don't need this anymore.
	pUnkn = NULL;

	
	m_bConnected = TRUE;
	m_pShutDownConnectionPoint->Init(this);

	((CTrendApp*)AfxGetApp())->DisplayText(_T("Successful to OPC server connected."));

	return TRUE;
}

BOOL CInfoServer::Disconnect()
{
	HRESULT hr = S_OK;
	
	CWaitCursor wait;

	if( m_pUnkn != NULL)
	{
		//remove groups
		int size = m_Groups.GetSize();
		for(int i = 0; i < size ; i++)
		{
			RemoveGroup(&m_Groups[0]);			
		}

		m_pShutDownConnectionPoint->Term(this);

		m_pUnkn.Release();	//since it is a CComPtr not needed, but we want to disconnect !
	}

	m_bConnected = FALSE;
	
	((CTrendApp*)AfxGetApp())->DisplayText(_T("Successful from OPC server disconnected."));

	return TRUE;
}

BOOL CInfoServer::IsConnected()
{
	return m_bConnected;
}

void CInfoServer::SetConnected(BOOL bConnected)
{
	m_bConnected = bConnected;
}

BOOL CInfoServer::AddGroup(CGroup** group)
{
	USES_CONVERSION;

	HRESULT		res;
	CIOPCServer	opcServer(m_pUnkn);
	CString		sGroup = _T("Trend"); //in  ome group for the whole app
	DWORD		dwLCID = 0; //in
	DWORD		dwUpdateRate = 100; //in
	BOOL		bActive = TRUE; //in
	long		lTimeBias = 0; //in
	float		fDeadBand = 1; //in

	DWORD		rate;	//out: servers rate
	IUnknown*	pUnkn; //out
	OPCHANDLE	hGroup; //out

	CGroup* new_group = new CGroup;

	res = opcServer.AddGroup(A2OLE(sGroup),
									bActive, dwUpdateRate, (OPCHANDLE)new_group,      
									&lTimeBias,
									&fDeadBand,
									dwLCID,
									&hGroup,
									&rate,
									IID_IOPCGroupStateMgt,
									(LPUNKNOWN*)&pUnkn);
	if(SUCCEEDED(res))
	{
		new_group->SetName(sGroup);
		new_group->SetHandle(hGroup);
		IOPCGroupStateMgt* pGRP = NULL;
		pUnkn->QueryInterface(IID_IOPCGroupStateMgt, (void**)&pGRP);
		new_group->SetInterface(pGRP);
		new_group->SetInfoServer(this);
		*group = new_group;
		m_Groups.Add(new_group);		

		/*
			no async trend read support

		// Establish a connection
		//
		CIDataObject	comDO(pGRP); 
		FORMATETC		fe;
		DWORD			dwConnection;

		fe.lindex = -1;
		fe.tymed = TYMED_HGLOBAL;
		fe.ptd = NULL;
		fe.dwAspect = DVASPECT_CONTENT;

		fe.cfFormat = RegisterClipboardFormat("OPCSTMFORMATDATATIME");
		res = comDO.DAdvise(&fe, ADVF_PRIMEFIRST, m_pAdviseSink, &dwConnection);
		if(FAILED(res))
		{
			DisplayError(res);
			comDO.DUnadvise(dwConnection);
			return FALSE;
		}
		else new_group->SetOPCSTMFormatDataTimeConnection(dwConnection);
*/

		return TRUE;
	}
	else
	{
		DisplayError(res);
		delete new_group;
		return FALSE;
	}
}

BOOL CInfoServer::RemoveGroup(CGroup** group)
{
	HRESULT			res;
	CIOPCServer		opcServer(m_pUnkn);
	int				nGroups, nItems;
	BOOL			bRet = FALSE;

	TRACE("Reference count should be 0 !");

	if(IsConnected())
	{
		res = opcServer.RemoveGroup((*group)->GetHandle(), TRUE); //force delete (even if references are outstanding)
		if(SUCCEEDED(res))
		{
			bRet = TRUE;
		}
		else
		{
			DisplayError(res);
			bRet = FALSE;
		}
	}
	else
	{
		bRet = FALSE;
	}

	//since following code handles only client memory it is always executed.
	nGroups = m_Groups.GetSize();
	for(int g = 0; g <  nGroups; g++)
	{
		if( *group == m_Groups[g] ) 
		{
			//delete the items (No RemoveItem() is necessary; RemoveGroups removes the items)
			CArray<CItem*, CItem*>*	pItems;
			nItems = m_Groups[g]->GetItems(&pItems);
			for(int i = 0; i < nItems ; i++)
			{
				CItem* pItem;
				pItem = (*pItems)[0];
				pItems->RemoveAt(0,1);
				delete pItem;
			}
			pItems->FreeExtra();

			delete *group;

			m_Groups.RemoveAt(g,1);
			m_Groups.FreeExtra();
			break;
		}
	}
				
	if(bRet) ((CTrendApp*)AfxGetApp())->DisplayText(_T("Group successfuly removed."));

	return bRet;
}


CComPtr<IUnknown> CInfoServer::GetInterface()
{
	return m_pUnkn;
}

unsigned int CInfoServer::GetGroups(CArray<CGroup*, CGroup*>** groups)
{
	*groups = &m_Groups;
	return((*groups)->GetSize());
}

BOOL CInfoServer::GetErrorString(HRESULT hr, CString& sErrorText)
{
	USES_CONVERSION;

	BOOL	bRet = FALSE;
	BOOL	bStringSet = FALSE;

	try
	{
		if((m_pUnkn != NULL) && IsConnected())
		{
			CIOPCServer	opcServer(m_pUnkn);
			LPWSTR		pErrorString = NULL;
			
			//returns error texts for OPC and windows errors
			hr = opcServer.GetErrorString(hr, 0, &pErrorString);
			if(SUCCEEDED(hr))
			{
				sErrorText = OLE2A(pErrorString);
				bRet = TRUE;
				bStringSet = TRUE;
			}
			
			CoTaskMemFree(pErrorString);
		}
	}
	catch(...)
	{
		//go ahead an try GetSystemErrorString
	}

	if(!bStringSet)
	{
		bRet = GetSystemErrorString(hr, sErrorText);
	}

	return bRet;
}

BOOL CInfoServer::GetSystemErrorString(HRESULT hr, CString& sErrorText)
{
	TCHAR* sMsg = NULL;
	CString sErrorHRESULT;

	try
	{
		if(HRESULT_FACILITY(hr) == FACILITY_WINDOWS)
			hr = HRESULT_CODE(hr);
			
		if(0 != FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
						 NULL,
						 hr,
						 MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
						 (LPTSTR)&sMsg, 0, NULL ))
		{
			sErrorHRESULT.Format(_T(" (%#x)."), hr);
			sErrorText = CString(sMsg) + sErrorHRESULT;
			LocalFree(sMsg);
			return TRUE;
		}
	}
	catch(...)
	{
		sErrorText = _T("Exception in CInfoServer::GetSystemErrorString()");
		TRACE(sErrorText);
	}

	return FALSE;
}

//for convinience
BOOL CInfoServer::DisplayError(HRESULT dwError)
{
	((CTrendApp*)AfxGetApp())->DisplayText(dwError);

	return TRUE;
}

void CInfoServer::SetOPCServer(CString sOPCServer)
{
	m_sOPCServer = sOPCServer;
}

CString CInfoServer::GetOPCServer()
{
	return m_sOPCServer;
}

void CInfoServer::SetOPCServerComputer(CString sOPCServerComputer)
{
	m_sOPCServerComputer = sOPCServerComputer;
}

CString CInfoServer::GetOPCServerComputer()
{
	return m_sOPCServerComputer;
}

CString CInfoServer::GetOPCServerName()
{
	return m_sOPCServerComputer + CString(_T("\\")) + m_sOPCServer;
}

void CInfoServer::SetOPCServerCLSID(CLSID clsidOPCServer)
{
	m_clsidOPCServer = clsidOPCServer;
}

CLSID CInfoServer::GetOPCServerCLSID()
{
	return m_clsidOPCServer;
}

//options
float  CInfoServer::GetOPCVersion()
{
	return m_fOPCVersion;
}

void  CInfoServer::SetOPCVersion(float opc_version)
{
	m_fOPCVersion = opc_version;
}

⌨️ 快捷键说明

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