📄 .#opcgroup.cpp.1.2
字号:
/*
OPCClientToolKit
Copyright (C) 2005 Mark C. Beharrell
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include "OPCServer.h"
#include "OPCGroup.h"
#include "OPCItem.h"
/**
* Handles OPC (DCOM) callbacks at the group level. It deals with the receipt of data from asynchronous operations.
* This is a fake COM object.
*/
class CAsynchDataCallback : public IOPCDataCallback
{
private:
DWORD mRefCount;
/**
* group this is a callback for
*/
COPCGroup &callbacksGroup;
/**
* enter a result of an asynchronous transaction into the tranaction object
*/
static void updateTransaction(CTransaction & trans, DWORD count, OPCHANDLE * clienthandles,
VARIANT* values, WORD * quality,FILETIME * time, HRESULT * errors){
// see page 136 - returned arrays may be out of order
for (unsigned i = 0; i < count; i++){
// TODO this is bad - server could corrupt address - need to use look up table
COPCItem * item = (COPCItem *)clienthandles[i];
if (FAILED(errors[i])){
trans.setItemError(item, errors[i]);
} else {
trans.setItemValue(item, time[i], quality[i], values[i], errors[i]);
}
}
}
public:
CAsynchDataCallback(COPCGroup &group):callbacksGroup(group){
mRefCount = 0;
}
~CAsynchDataCallback(){
}
/**
* Functions associated with IUNKNOWN
*/
STDMETHODIMP QueryInterface( REFIID iid, LPVOID* ppInterface){
if ( ppInterface == NULL){
return E_INVALIDARG;
}
if ( iid == IID_IUnknown ){
*ppInterface = (IUnknown*) this;
} else if ( iid == IID_IOPCDataCallback){
*ppInterface = (IOPCDataCallback*) this;
} else
{
*ppInterface = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) AddRef(){
return ++mRefCount;
}
STDMETHODIMP_(ULONG) Release(){
--mRefCount;
if ( mRefCount == 0){
delete this;
}
return mRefCount;
}
/**
* Functions associated with IOPCDataCallback
*/
STDMETHODIMP OnDataChange(DWORD Transid, OPCHANDLE grphandle, HRESULT masterquality,
HRESULT mastererror, DWORD count, OPCHANDLE * clienthandles,
VARIANT * values, WORD * quality, FILETIME * time,
HRESULT * errors)
{
if (Transid != 0){
// it is a result of a refresh (see p106 of spec)
CTransaction & trans = *(CTransaction *)Transid;
updateTransaction(trans, count, clienthandles, values,quality,time,errors);
trans.setCompleted();
if (trans.shouldPassToAsynch()){
// TODO - implement pass to ASYNCH
}
return S_OK;
}
CAtlArray<AsynchOPCItemData> asynchOpcItemData;
for (unsigned i = 0; i < count; i++){
COPCItem * item = (COPCItem *)clienthandles[i];
asynchOpcItemData.Add(AsynchOPCItemData(item,time[i], quality[i], values[i], errors[i]));
}
IAsynchDataCallback * usrHandler = callbacksGroup.getUsrAsynchHandler();
if (usrHandler){
usrHandler->OnDataChange(callbacksGroup, asynchOpcItemData);
}
return S_OK;
}
STDMETHODIMP OnReadComplete(DWORD Transid, OPCHANDLE grphandle,
HRESULT masterquality, HRESULT mastererror, DWORD count,
OPCHANDLE * clienthandles, VARIANT* values, WORD * quality,
FILETIME * time, HRESULT * errors)
{
// TODO this is bad - server could corrupt address - need to use look up table
CTransaction & trans = *(CTransaction *)Transid;
updateTransaction(trans, count, clienthandles, values,quality,time,errors);
trans.setCompleted();
return S_OK;
}
STDMETHODIMP OnWriteComplete(DWORD Transid, OPCHANDLE grphandle, HRESULT mastererr,
DWORD count, OPCHANDLE * clienthandles, HRESULT * errors)
{
// TODO this is bad - server could corrupt address - need to use look up table
CTransaction & trans = *(CTransaction *)Transid;
// see page 145 - number of items returned may be less than sent
for (unsigned i = 0; i < count; i++){
// TODO this is bad - server could corrupt address - need to use look up table
COPCItem * item = (COPCItem *)clienthandles[i];
trans.setItemError(item, errors[i]); // this records error state - may be good
}
trans.setCompleted();
return S_OK;
}
STDMETHODIMP OnCancelComplete(DWORD transid, OPCHANDLE grphandle){
printf("OnCancelComplete: Transid=%ld GrpHandle=%ld\n", transid, grphandle);
return S_OK;
}
};
COPCGroup::COPCGroup(const CString & groupName, bool active, unsigned long reqUpdateRate_ms, unsigned long &revisedUpdateRate_ms, float deadBand, COPCServer &server):
name(groupName),
opcServer(server)
{
USES_CONVERSION;
WCHAR* wideName = T2OLE(groupName);
HRESULT result = opcServer.getServerInterface()->AddGroup(wideName, active, reqUpdateRate_ms, 0, 0, &deadBand,
0, &groupHandle, &revisedUpdateRate_ms, IID_IOPCGroupStateMgt, (LPUNKNOWN*)&iStateManagement);
if (FAILED(result))
{
throw OPCException("Failed to Add group");
}
result = iStateManagement->QueryInterface(IID_IOPCSyncIO, (void**)&iSychIO);
if (FAILED(result)){
throw OPCException("Failed to get IID_IOPCSyncIO");
}
result = iStateManagement->QueryInterface(IID_IOPCAsyncIO2, (void**)&iAsych2IO);
if (FAILED(result)){
throw OPCException("Failed to get IID_IOPCAsyncIO2");
}
result = iStateManagement->QueryInterface(IID_IOPCItemMgt, (void**)&iItemManagement);
if (FAILED(result)){
throw OPCException("Failed to get IID_IOPCItemMgt");
}
}
COPCGroup::~COPCGroup()
{
opcServer.getServerInterface()->RemoveGroup(groupHandle, FALSE);
}
void COPCGroup::readSync(int noItems, COPCItem **items, OPCItemData data[], HRESULT errors[], OPCDATASOURCE source){
OPCHANDLE *handles = new OPCHANDLE[noItems];
for (int i = 0; i < noItems; i++){
if ((items[i]->getAccessRights() && OPC_READABLE) != OPC_READABLE){
throw OPCException("Item is not readable");
}
handles[i] = items[i]->getHandle();
}
HRESULT *itemResult;
OPCITEMSTATE *itemState;
HRESULT result = iSychIO->Read(source, noItems, handles, &itemState, &itemResult);
if (FAILED(result))
{
throw OPCException("Read failed");
}
for (i = 0; i < noItems; i++){
errors[i] = itemResult[i];
if (!FAILED(itemResult[i])){
data[i].set(itemState[i]);
VariantClear(&itemState[i].vDataValue);
}
}
COPCClient::comFree(itemResult);
COPCClient::comFree(itemState);
}
CTransaction * COPCGroup::refresh(OPCDATASOURCE source,/* bool passToAsynch,*/ ITransactionComplete *transactionCB){
DWORD cancelID;
CTransaction * trans = new CTransaction(items, /*passToAsynch*/false, transactionCB);
HRESULT result = iAsych2IO->Refresh2(source, (DWORD)trans, &cancelID);
if (FAILED(result)){
delete trans;
throw OPCException("refresh failed");
}
return trans;
}
COPCItem * COPCGroup::addItem(CString &itemName, bool active)
{
COPCItem * item = new COPCItem(itemName, active, *this);
items.Add(item);
return item;
}
int COPCGroup::addItems(CAtlArray<CString>& itemName, CAtlArray<COPCItem *>& itemsCreated, bool active){
// this does not work
OPCITEMDEF *itemDef = new OPCITEMDEF[itemName.GetCount()];
for (unsigned i = 0; i < itemName.GetCount(); i++){
USES_CONVERSION;
WCHAR* wideName = T2OLE(itemName[i]);
itemDef[i].szItemID = wideName;
itemDef[i].szAccessPath = wideName;
itemDef[i].bActive = active;
itemDef[i].hClient = (DWORD)this;
itemDef[i].dwBlobSize = 0;
itemDef[i].pBlob = NULL;
itemDef[i].vtRequestedDataType = VT_EMPTY;
}
HRESULT *itemResult;
OPCITEMRESULT *itemDetails;
HRESULT result = getItemManagementInterface()->AddItems(itemName.GetCount(), itemDef, &itemDetails, &itemResult);
if (FAILED(result)){
throw OPCException("Failed to add items");
}
int errorCount = 0;
for (i = 0; i < itemName.GetCount(); i++){
if(itemDetails[i].pBlob){
COPCClient::comFree(itemDetails[0].pBlob);
}
if (FAILED(itemResult[i])){
errorCount++;
}
OPCHANDLE serversItemHandle = itemDetails[i].hServer;
VARTYPE vtCanonicalDataType = itemDetails[i].vtCanonicalDataType;
DWORD dwAccessRights = itemDetails[i].dwAccessRights;
}
COPCClient::comFree(itemDetails);
COPCClient::comFree(itemResult);
return errorCount;
}
void COPCGroup::enableAsynch(IAsynchDataCallback &handler){
if (!asynchDataCallBackHandler == false){
throw OPCException("Asynch already enabled");
}
ATL::CComPtr<IConnectionPointContainer> iConnectionPointContainer = 0;
HRESULT result = iStateManagement->QueryInterface(IID_IConnectionPointContainer, (void**)&iConnectionPointContainer);
if (FAILED(result))
{
throw OPCException("Could not get IID_IConnectionPointContainer");
}
result = iConnectionPointContainer->FindConnectionPoint(IID_IOPCDataCallback, &iAsynchDataCallbackConnectionPoint);
if (FAILED(result))
{
throw OPCException("Could not get IID_IOPCDataCallback");
}
asynchDataCallBackHandler = new CAsynchDataCallback(*this);
result = iAsynchDataCallbackConnectionPoint->Advise(asynchDataCallBackHandler, &callbackHandle);
if (FAILED(result))
{
iAsynchDataCallbackConnectionPoint = NULL;
asynchDataCallBackHandler = NULL;
throw OPCException("Failed to set DataCallbackConnectionPoint");
}
userAsynchCBHandler = &handler;
}
void COPCGroup::setState(DWORD reqUpdateRate_ms, DWORD &returnedUpdateRate_ms, float deadBand, BOOL active){
HRESULT result = iStateManagement->SetState(&reqUpdateRate_ms, &returnedUpdateRate_ms, &active,0, &deadBand,0,0);
if (FAILED(result))
{
throw OPCException("Failed to set group state");
}
}
void COPCGroup::disableAsynch(){
if (asynchDataCallBackHandler == NULL){
throw OPCException("Asynch is not exabled");
}
iAsynchDataCallbackConnectionPoint->Unadvise(callbackHandle);
iAsynchDataCallbackConnectionPoint = NULL;
asynchDataCallBackHandler = NULL;// WE DO NOT DELETE callbackHandler, let the COM ref counting take care of that
userAsynchCBHandler = NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -