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

📄 opcdrvserver.cpp

📁 基于Intellution开发包的开发的OPC服务器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// OPCDrvServer.cpp
//
//  This file contains the implementation of the Server object.
//
// This implementation uses 'tear off' interfaces
// (I.e. the interfaces are separate from the object 
//  which supports only IUnknown)
//
//
//	(c) COPYRIGHT 1996-1998, INTELLUTION INC.
// ALL RIGHTS RESERVED
//
//
//	Functions defined in this module:
//
//			COPCDrvServer::COPCDrvServer()
//			COPCDrvServer::~COPCDrvServer()
//			COPCDrvServer::AddRef()
//			COPCDrvServer::Release()
//			COPCDrvServer::QueryInterface()
//			COPCDrvServer::Init()
//			COPCDrvServer::GetNameList()
//			COPCDrvServer::FreeNameList()
//			COPCDrvServer::GetUnkList()
//			COPCDrvServer::FreeUnkList()
//			COPCDrvServer::UpdateDataCache()
//			COPCDrvServer::GetDriverInfo()
//			COPCDrvServer::IsDataTypeSupported()
//			COPCDrvServer::SendMessageToDriver()
//			COPCDrvServer::PollThread()
//
//
//
// Modification Log:
//	Vers	Date     By		Notes
//	----	-------- ---	-----
//	1.0		08/26/97 jra	Created
//	1.3		03/10/98 jra	Modified to be wizard generated and driver specific.
//
//

#define WIN32_LEAN_AND_MEAN

#include "OpcStdAfx.h"
#include <AFXCONV.h>
#include <process.h>

#include "OPCDrv.h"
#include "OPCDrvThread.h"
#include "..\server\interfaces\InterfaceDef_i.c"
// added support for OSDKPS.dll
#include <OSDKDefs_i.c>
#include "NioFuncs.h"

extern BOOL		ChangeDriverThreadPriority(DWORD dwPriority);
extern DWORD	g_dwWaitPeriod;
extern DWORD	g_dwServerThreadPriority;
extern TCHAR	g_tszAcronym[];
extern FILETIME	g_ftStartTime;


/////////////////////////////////////////////////////////////////////////////
// Constructor /Destructor functions
//

////////////////////////////////////////////////////////////////
// COPCDrvServer()
//
// Constructor for the main server object
//
////////////////////////////////////////////////////////////////
COPCDrvServer::COPCDrvServer(LPUNKNOWN	pOuter, 
							 void		(*pfn)(void))
{
	// Init reference count to 0
	//
	m_lRefCount					= 0;

	// Clear out 'tear-off' interface ptrs
	// The interfaces will be created as needed in QueryInterface
	//
	m_pCImpIOPCServer			= NULL;
	m_pCImpIOPCBrowseServer		= NULL;
	m_pCImpIPersistFile			= NULL;

	m_dwBandwidth				= 0;
	m_ServerState				= OPC_STATUS_NOCONFIG;

	// Used to calculate bandwidth
	//
	m_dwNumGroupsProcessed		= 0;
	m_dwTotalPasses				= 0;
	m_bKeepRunning				= TRUE;

	m_dwLastTickCount			= 0;

	// Get current UTC Time and store it
	//
	CoFileTimeNow(&m_ftLastUpdate);
	m_ftServerStartTime = g_ftStartTime;

	m_pfnDestroy				= pfn;
	m_lTransactionID			= 0;
	m_Slot						= 0;
	m_dwPollThreadId			= 0L;

	// Management of the groups
	//
	m_dwNumGroups				= 0;

	// Initialize the Group hash table to a prime number
	//
	m_mapGroup.InitHashTable(31);

	InitializeCriticalSection(&this->m_Lock);

	// Hardware options stuff
	//
	m_nOptionsSize				= 0;
	m_nNumOptions				= 0;
	m_pszOptions				= NULL;
	m_pvtOptionValues			= NULL;

	// I/O Server interface stuff
	//
	m_pIDriver					= NULL;
	m_pIDriverMessage			= NULL;
	m_pIDriverMessageMarshalled	= NULL;
	m_pIOpcConnections			= NULL;
	m_pIDriverMessageStream		= NULL;
}


////////////////////////////////////////////////////////////////
// ~COPCDrvServer()
//
// Destructor for the main server object
//
////////////////////////////////////////////////////////////////
COPCDrvServer::~COPCDrvServer(void)
{
	// Shutdown the bandwidth thread
	//
	m_bKeepRunning = FALSE;

	// First, turn off any background processing
	//
	ClearServerSlot(m_Slot);

	// Wait for the threads to shutdown.
	//
	if (WaitForSingleObject(m_hPollThread, 
							THREAD_SHUTDOWN_TIME) == WAIT_TIMEOUT)
	{
		TerminateThread(m_hPollThread, 0);
	}

	// Lock out this server
	//
	Lock();

	// If necessary free any memory associated with the Group map
	//
	FreeAllGroups();

	// Then delete any tear off interfaces
	//
	if (m_pCImpIOPCServer)
	{
		delete m_pCImpIOPCServer;
	}
	if (m_pCImpIPersistFile)
	{
		delete m_pCImpIPersistFile;
	}
	if (m_pCImpIOPCBrowseServer)
	{
		delete m_pCImpIOPCBrowseServer;
	}

	// Delete the hardware options lists
	//
	if (m_pszOptions)
	{
		delete [] m_pszOptions;
	}
	if (m_pvtOptionValues)
	{
		delete [] m_pvtOptionValues;
	}

	// Inform NIO that we are unloading if this is the last one
	//
	if (0 == GetServerSlotCount())
	{
		IOSTAT	IoStat;

		memset(&IoStat, 0, sizeof(IOSTAT));
		nio_CleanUp(&IoStat);
		if (IoStat.iostatus != FE_OK)
		{
			HRESULT hr = (HRESULT)((IoStat.aux1 << 16) | IoStat.aux2);
			CString szMsg;

			szMsg.Format("nio_CleanUp() failed. Returned code = %lX", hr);
			SendMessageToDriver(szMsg, MSG_DEBUG);
		}
	}

	// Disconnect from the automation interface
	//
	if (m_pIDriverMessage)
	{
		m_pIDriverMessage->Release();
	}
	if (m_pIOpcConnections)
	{
		long lRef = 0L;
		m_pIOpcConnections->GetOpcRef(&lRef);
		m_pIOpcConnections->Release();
	}
	if (m_pIDriver)
	{
		m_pIDriver->Release();
	}

	UnLock();
	DeleteCriticalSection(&this->m_Lock);
}


/////////////////////////////////////////////////////////////////////////////
// IUnknown functions
//

////////////////////////////////////////////////////////////////
// IUnknown::AddRef()
//
// Standard IUnknown implementation
//
////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) COPCDrvServer::AddRef(void)
{
	return InterlockedIncrement(&m_lRefCount);
}


////////////////////////////////////////////////////////////////
// IUnknown::Release()
//   Standard IUnknown implementation
//
////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) COPCDrvServer::Release(void)
{
	ASSERT(0 != m_lRefCount);

	ULONG currentCount = InterlockedDecrement(&m_lRefCount);

	// If no references left for this server
	if (currentCount == 0)
	{
		// Then delete this server.
		//
		if(m_pfnDestroy) 
		{
			(*m_pfnDestroy)();	// DLL can unload if last one
		}

		delete this;
	}

	return currentCount;
}


////////////////////////////////////////////////////////////////
// IUnknown::QueryInterface()
//
// Standard IUnknown implementation using 'tear off' interfaces
//
////////////////////////////////////////////////////////////////
STDMETHODIMP COPCDrvServer::QueryInterface(REFIID	iid, 
										   LPVOID	*ppInterface)
{
	// Make sure we got a valid pointer
	//
	if (NULL == ppInterface)
	{
		return E_INVALIDARG;
	}	

	// IUnknown
	if (iid == IID_IUnknown)
	{
		*ppInterface = (IUnknown *)this;
	}
	// IOPCServer
	else if (iid == IID_IOPCServer)
	{
		if(NULL == m_pCImpIOPCServer) 
		{
			m_pCImpIOPCServer = new CImpIOPCServer(this);
		}
		if (NULL == m_pCImpIOPCServer)
		{
			return E_OUTOFMEMORY;
		}
		*ppInterface = m_pCImpIOPCServer;
	}
	// IOPCBrowseServerAddressSpace
	else if (iid == IID_IOPCBrowseServerAddressSpace)
	{
		if(NULL == m_pCImpIOPCBrowseServer)
		{
			m_pCImpIOPCBrowseServer = new CImpIOPCBrowseServer(this);
		}
		if (NULL == m_pCImpIOPCBrowseServer)
		{
			return E_OUTOFMEMORY;
		}
		*ppInterface = m_pCImpIOPCBrowseServer;
	}
	// IPersistFile
	else if ((iid == IID_IPersistFile) || (iid == IID_IPersist))
	{
		if(NULL == m_pCImpIPersistFile) 
		{
			m_pCImpIPersistFile = new CImpIPersistFile(this);
		}
		if (NULL == m_pCImpIPersistFile)
		{
			return E_OUTOFMEMORY;
		}
		*ppInterface = m_pCImpIPersistFile;
	}
	// IEnumUnknown
	else if (iid == IID_IEnumUnknown)
	{
		// Note enumerators are special in that they are independent objects
		// They are not just interfaces on an existing object
		//
		HRESULT				hr;
		CImpIEnumUnknown	*temp;
		LPUNKNOWN			*GroupList;
		int					nGroupCount;

		// Get a snapshot of the group list 
		// (Note this does NOT do AddRefs to the groups - but see IXXXEnum below)
		//
		GetUnkList(OPC_ENUM_ALL_CONNECTIONS, &GroupList, &nGroupCount);

		// Create the Enumerator using the snapshot (which might be empty)
		// Note that the enumerator constructor will AddRef 
		// all of the groups.
		//
		temp = new CImpIEnumUnknown(this, nGroupCount, GroupList, pIMalloc);
		delete [] GroupList;

		if (NULL == temp)
		{
			return E_OUTOFMEMORY;
		}

		// Then QI for the interface ('temp') actually is the interface
		// but QI is the 'proper' way to get it.
		// Note QI will do an AddRef of the Enum which will also do
		// an AddRef of the 'parent' - i.e. the 'this' pointer passed above.
		//
		hr = temp->QueryInterface(iid, ppInterface);
		if (FAILED(hr))
		{
			delete temp;
			return hr;
		}

		// If all OK - return here 
		// Unlike most interfaces this one does NOT directly addref the server
		// (since we created a new and independent object)
		//
		return S_OK;
	}
	// No interface available
	else
	{
		*ppInterface = NULL;
	}
	
	if (NULL == *ppInterface)
	{
		return E_NOINTERFACE;
	}

	// Record the reference to the new object.
	//
	((LPUNKNOWN)*ppInterface)->AddRef();
	return S_OK;
}


/////////////////////////////////////////////////////////////////////////////
// Private (non-OPC) Utility Functions
//


////////////////////////////////////////////////////////////////
// COPCDrvServer::Init()
//
// Initializes the object
//
// Returns:
//	S_OK		success
//	E_FAIL		failure
//
////////////////////////////////////////////////////////////////
HRESULT COPCDrvServer::Init(void)
{
	// Connect to the driver's automation interface
	//
	if (FAILED(GetDriverInfo()))
	{
		m_pIDriver = NULL;
		m_pIDriverMessage = NULL;
		LogEventMessage(TEXT("CoCreateInstance() failed. Unable to connect to automation interface"),
						g_tszAcronym,
						3);
		return E_FAIL;
	}

	// Fire off the main poll thread that does all of the work
	//
	unsigned int nAddress = 0;
	m_hPollThread = (HANDLE)_beginthreadex(NULL,
										   0,
										   PollThread, 
										   (LPVOID)this, 
										   0, 
										   &nAddress);
	if (NULL == m_hPollThread)
	{
		LogEventMessage(TEXT("_beginthreadex failed. Unalbe to create polling thread"),
						g_tszAcronym,
						3);
		return E_FAIL;
	}

	// Plug this server into the map for bandwidth calculations.
	//
	if (!FindServerSlot(&m_Slot, this))
	{
		LogEventMessage(TEXT("Unable to initialize server object"),
						g_tszAcronym,
						3);
	}

	return S_OK;
}


////////////////////////////////////////////////////////////////
// COPCDrvServer::GetNameList()
//
// Create a list of all the group names.
//
// Returns:
//	void
//
////////////////////////////////////////////////////////////////
void COPCDrvServer::GetNameList(OPCENUMSCOPE	OPCScope, 
								LPOLESTR		**ppGroupList, 
								int				*pnGroupCount)
{
	int				nNumGroups	= 0,
					i			= 0;
	LPOLESTR		*mylist		= NULL;
	OPCHANDLE		OPCHandle	= 0;
	COPCDrvGroup	*pGroup		= NULL;
	POSITION		posGroup;


	// Initialize return parameters
	*ppGroupList = NULL;
	*pnGroupCount = 0;

	// Lock the server object
	//
	this->Lock();

	// Get the info about the group list
	//
	nNumGroups	= this->GetNumGroupHandles();
	posGroup	= this->GetFirstGroupPosition();

	// See if there is anything to enumerate
	//
	if (0 == nNumGroups)
	{
		this->UnLock();
		return;
	}

	switch(OPCScope)
	{
	case OPC_ENUM_PRIVATE_CONNECTIONS:
	case OPC_ENUM_PRIVATE:
	case OPC_ENUM_ALL_CONNECTIONS:
	case OPC_ENUM_ALL:
		*ppGroupList = mylist = new LPOLESTR[nNumGroups];	// Caller must free this!
		if (*mylist == NULL)
		{
			this->UnLock();
			return;
		}
		for (i = 0; i < nNumGroups; i++)
		{
			this->GetNextGroup(posGroup, OPCHandle, pGroup);

			// Note that the string is cloned to keep the enumerator 'stable'
			//
			mylist[*pnGroupCount] = WSTRClone(pGroup->m_szName, NULL);
			(*pnGroupCount)++;
		}
		break;

	case OPC_ENUM_PUBLIC:
	case OPC_ENUM_PUBLIC_CONNECTIONS:
		break;
	default:
		// Should never happen!!
		TRACE("Invalid scope passed to GetNameList() (%d), File %s, Line %d\n", 
			OPCScope, __FILE__, __LINE__);
		break;
	}

	// Unlock the server object
	//
	this->UnLock();
}


////////////////////////////////////////////////////////////////
// COPCDrvServer::FreeNameList()
//
// Free a list of group names.
//
// Returns:
//	void
//
////////////////////////////////////////////////////////////////
void COPCDrvServer::FreeNameList(LPOLESTR	*ppGroupList, 
								 int		nCount)
{

⌨️ 快捷键说明

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