www.pudn.com > Ge_opc_Server_v1.rar > I_ASIO.CPP
// i_asio.cpp
//
// This file contains the implementation of
// the IOPCASyncIO interface for groups in the LHEpipeview server.
//
//
// (c) COPYRIGHT 1996,1997 INTELLUTION INC.
// ALL RIGHTS RESERVED
//
// Original Author: Al Chisholm
//
// Modification Log:
// Vers Date By Notes
// ---- -------- --- -----
// 0.00 11/18/96 ACC stubs
// 0.90 04/08/97 ACC add async logic
//
//
#define WIN32_LEAN_AND_MEAN
#include "OPCLHEpipeview.h"
#include "OPCERROR.h"
extern CRITICAL_SECTION CritSec;
/////////////////////////////////////////////////////////////////////////////
// Constructor /Destructor functions
//
///////////////////////////////////////
// ILHEpipeviewASIO()
// Constructor for this Interface
///////////////////////////////////////
ILHEpipeviewASIO::ILHEpipeviewASIO( LPUNKNOWN parent )
{
m_Parent = (LHEpipeviewGroup *)parent;
}
///////////////////////////////////////
// ~ILHEpipeviewASIO()
// Destructor for this Interface
///////////////////////////////////////
ILHEpipeviewASIO::~ILHEpipeviewASIO( void)
{
m_Parent->m_pILHEpipeviewASIO = 0;
}
/////////////////////////////////////////////////////////////////////////////
// IUnknown functions Delegate to Parent
//
STDMETHODIMP_(ULONG) ILHEpipeviewASIO::AddRef( void)
{
return m_Parent->AddRef();
}
STDMETHODIMP_(ULONG) ILHEpipeviewASIO::Release( void)
{
return m_Parent->Release();
}
STDMETHODIMP ILHEpipeviewASIO::QueryInterface( REFIID iid, LPVOID* ppInterface)
{
return m_Parent->QueryInterface(iid, ppInterface);
}
/////////////////////////////////////////////////////////////////////////////
// ILHEpipeviewASIO (IOPCAsyncIO) interface functions
//
///////////////////////////////////////
// Read
// Queue up an Async read.
//
///////////////////////////////////////
STDMETHODIMP ILHEpipeviewASIO::Read(
DWORD dwConnection,
OPCDATASOURCE dwSource,
DWORD dwNumItems,
OPCHANDLE * phServer,
DWORD * pTransactionID,
HRESULT ** ppErrors
)
{
LHEpipeviewGroup &g = *m_Parent;
LHEpipeviewServer &s = *g.m_ParentServer;
unsigned int j;
int reject = 0;
HRESULT *pe = 0;
// Sanity Check
//
if(dwNumItems == 0) return E_INVALIDARG;
if(phServer == NULL) return E_INVALIDARG;
if(pTransactionID == NULL) return E_INVALIDARG;
if(ppErrors == NULL) return E_INVALIDARG;
// This sample supports only 1 outstanding async read per group
//
if(g.m_AsyncReadActive) return CONNECT_E_ADVISELIMIT;
// Alloc memory for returned error list
// and the stored handle list (to be returned later in the callback)
//
pe = *ppErrors = (HRESULT*)pIMalloc->Alloc(dwNumItems * sizeof( HRESULT ));
if(pe == NULL) return E_OUTOFMEMORY;
// Store the list of items to be read
// so that the background thread knows which ones to 'watch'
// Note that many different implementations of this are possible.
//
g.m_AsyncReadList = (OPCHANDLE*)pIMalloc->Alloc(dwNumItems * sizeof( OPCHANDLE ));
if(g.m_AsyncReadList == NULL)
{
pIMalloc->Free(pe);
return E_OUTOFMEMORY;
}
EnterCriticalSection(&CritSec);
// First, validate ALL of the handles
//
for (j=0; jFree(g.m_AsyncReadList);
LeaveCriticalSection(&CritSec);
return OPC_E_INVALIDHANDLE;
}
// If all handles are good, then que up async reads of the items
// (exact implementation of this will be server specific)
//
for (j=0; jQueDeviceRead(DEVICE_READ);
}
// it all worked - the read is in progress
//
s.GenerateTransaction(pTransactionID);
g.m_AsyncReadTID = *pTransactionID;
g.m_AsyncReadCancel = 0;
g.m_AsyncReadSource = dwSource;
g.m_AsyncReadActive = dwNumItems; // record number of items
LeaveCriticalSection(&CritSec);
return S_OK;
}
///////////////////////////////////////
// Write
// Queue up an Async Write.
//
///////////////////////////////////////
STDMETHODIMP ILHEpipeviewASIO::Write(
DWORD dwConnection,
DWORD dwNumItems,
OPCHANDLE * phServer,
VARIANT * pItemValues,
DWORD * pTransactionID,
HRESULT ** ppErrors
)
{
LHEpipeviewGroup &g = *m_Parent;
LHEpipeviewServer &s = *g.m_ParentServer;
unsigned int j;
int reject = 0;
HRESULT *pe = 0;
// Sanity Check
//
if(dwNumItems == 0) return E_INVALIDARG;
if(phServer == NULL) return E_INVALIDARG;
if(pTransactionID == NULL) return E_INVALIDARG;
if(pItemValues == NULL) return E_INVALIDARG;
if(ppErrors == NULL) return E_INVALIDARG;
// This sample supports only 1 outstanding async write per group
//
if(g.m_AsyncWriteActive) return CONNECT_E_ADVISELIMIT;
// Alloc memory for returned error list
// and the stored handle list (to be returned later in the callback)
//
pe = *ppErrors = (HRESULT*)pIMalloc->Alloc(dwNumItems * sizeof( HRESULT ));
if(pe == NULL) return E_OUTOFMEMORY;
// Store the list of items to be written
// so that the background thread knows which ones to 'watch'
// Note that many different implementations of this are possible.
//
g.m_AsyncWriteList = (OPCHANDLE*)pIMalloc->Alloc(dwNumItems * sizeof( OPCHANDLE ));
if(g.m_AsyncWriteList == NULL)
{
pIMalloc->Free(pe);
return E_OUTOFMEMORY;
}
EnterCriticalSection(&CritSec);
// First, validate ALL of the handles
//
for (j=0; jFree(g.m_AsyncWriteList);
LeaveCriticalSection(&CritSec);
return OPC_E_INVALIDHANDLE;
}
// If all handles are good, then que up async writes of the items
// (exact implementation of this will be server specific)
//
for (j=0; jQueDeviceWrite( &pItemValues[j] );
}
// it all worked - the write is in progress
//
s.GenerateTransaction(pTransactionID);
g.m_AsyncWriteTID = *pTransactionID;
g.m_AsyncWriteCancel = 0;
g.m_AsyncWriteActive = dwNumItems; // record number of items
LeaveCriticalSection(&CritSec);
return S_OK;
}
///////////////////////////////////////
// Refresh
// Queue up an Async refresh
// (which is a cross between async read and ondatachange).
//
///////////////////////////////////////
STDMETHODIMP ILHEpipeviewASIO::Refresh(
DWORD dwConnection,
OPCDATASOURCE dwSource,
DWORD * pTransactionID
)
{
int j;
LHEpipeviewGroup &g = *m_Parent;
LHEpipeviewServer &s = *g.m_ParentServer;
int Count;
EnterCriticalSection(&CritSec);
// Count active items in group
//
Count = 0;
if (g.m_bActive) for (j=0; jm_bActive)
Count++;
}
}
// If nothing active, return FAIL (per spec)
//
if(Count == 0)
{
LeaveCriticalSection(&CritSec);
return E_FAIL;
}
// Store the list of items to be returned (all of them)
// so that the background thread knows which ones to 'watch'.
// This is treated somewhat like an async read of 'all'
// Note that many different implementations of this are possible.
//
// In this case since we have created an explicit list of items to watch,
// we do not need to artificaly mark them as changed.
//
g.m_RefreshList = (OPCHANDLE*)pIMalloc->Alloc(Count * sizeof( OPCHANDLE ));
if(g.m_RefreshList == NULL)
{
LeaveCriticalSection(&CritSec);
return E_OUTOFMEMORY;
}
// For each item in group
//
Count = 0;
for (j=0; jQueDeviceRead(DEVICE_REFRESH);
Count++;
}
}
// the refresh is in progress
//
s.GenerateTransaction(pTransactionID);
g.m_RefreshTID = *pTransactionID;
g.m_RefreshCancel = 0;
g.m_RefreshSource = dwSource;
g.m_RefreshActive = Count;
LeaveCriticalSection(&CritSec);
return S_OK;
}
///////////////////////////////////////
// Cancel
///////////////////////////////////////
STDMETHODIMP ILHEpipeviewASIO::Cancel(
DWORD dwTransactionID
)
{
LHEpipeviewGroup &g = *m_Parent;
// search for this transaction
//
if(g.m_AsyncReadActive &&
(g.m_AsyncReadTID == dwTransactionID))
{
g.m_AsyncReadCancel = 1;
return S_OK;
}
if(g.m_AsyncWriteActive &&
(g.m_AsyncWriteTID == dwTransactionID))
{
g.m_AsyncWriteCancel = 1;
return S_OK;
}
if(g.m_RefreshActive &&
(g.m_RefreshTID == dwTransactionID))
{
g.m_RefreshCancel = 1;
return S_OK;
}
return E_FAIL;
}