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; 
}