📄 infoserver.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 + -