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

📄 opcdrvserver.cpp

📁 基于Intellution开发包的开发的OPC服务器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	if(!nCount) 
	{
		return;
	}

	for(int j = 0; j < nCount; j++)
	{
		delete [] ppGroupList[j];
	}
	delete [] ppGroupList;
}


////////////////////////////////////////////////////////////////
// COPCDrvServer::GetUnkList()
//
// Create a list of all the group Unknown Pointers
// Note that we do NOT AddRef the pointers here - that will be
// done when the caller calls Next() in the enumerator.
//
// Returns:
//	void
//
////////////////////////////////////////////////////////////////
void COPCDrvServer::GetUnkList(OPCENUMSCOPE		OPCScope, 
							   LPUNKNOWN		**ppGroupList, 
							   int				*pnGroupCount)
{
	int				nNumGroups,
					i = 0;
	LPUNKNOWN		*mylist;
	POSITION		posGroup;
	OPCHANDLE		OPCHandle = 0;
	COPCDrvGroup	*pGroup = NULL;


	// 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 LPUNKNOWN[nNumGroups];	// caller must free this!!
		if (NULL == *mylist)
		{
			this->UnLock();
			return;
		}

		for (; i < nNumGroups; i++)
		{
			this->GetNextGroup(posGroup, OPCHandle, pGroup);

			mylist[*pnGroupCount] = (LPUNKNOWN)pGroup;
			(*pnGroupCount)++;
		}
		break;

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

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


////////////////////////////////////////////////////////////////
// COPCDrvServer::FreeUnkList()
//
// Free a list of group pointers.
// Note that since GetUnkList did not addref, we do not release.
//
// Returns:
//	void
//
////////////////////////////////////////////////////////////////
void COPCDrvServer::FreeUnkList(LPUNKNOWN	*ppGroupList, 
								int			nCount)
{
	if(!nCount)
	{
		return;
	}

	delete [] ppGroupList;
}


////////////////////////////////////////////////////////////////
// COPCDrvServer::UpdateDataCache()
//
// Update all items internal data cache.
// Handle any async operations including Data Refresh.
//
// Returns:
//	void
// 
//////////////////////////////////////////////////////////////////
void COPCDrvServer::UpdateDataCache(DWORD dwTics)
{
	DWORD			dwStartTics	= GetTickCount();
	POSITION		posGroup;
	OPCHANDLE		OPCHandle	= 0;
	COPCDrvGroup	*pGroup		= NULL;


	Lock();
	
	// For each possible group in server...
	//
	posGroup = GetFirstGroupPosition();
	while (NULL != posGroup)
	{
		GetNextGroup(posGroup, OPCHandle, pGroup);

		// Allow the group to perform any asynchronous tasks.
		//
		pGroup->Lock();
		pGroup->GroupProcess(dwTics + GetTickCount() - dwStartTics);
		pGroup->UnLock();
	}

	UnLock();
}


////////////////////////////////////////////////////////////////
// COPCDrvServer::GenerateTransaction()
//
// This function creates a new, unique transaction ID.
//
// Returns:
//	void
//
////////////////////////////////////////////////////////////////
void COPCDrvServer::GenerateTransaction(DWORD *pTID)
{
	InterlockedIncrement(&m_lTransactionID);

	// 0 is not a legal TID so compensate for it
	//
	if(0 == m_lTransactionID) 
	{
		InterlockedIncrement(&m_lTransactionID);
	}
	*pTID = m_lTransactionID;
}


////////////////////////////////////////////////////////////////
// COPCDrvServer::GetDriverInfo()
//
// This function connects to the OLE Automation interface on the
// I/O Server. It also determines what datatype the server supports.
//
// Returns:
//	HRESULT	- Any valid return from CoCreateInstance()
//
////////////////////////////////////////////////////////////////
HRESULT COPCDrvServer::GetDriverInfo(void)
{
	HRESULT	hrRet		= S_OK,
			hr;
	IOSTAT	IoStat,
			*pIoStat	= &IoStat;


	// Find out how big or a buffer we need to hold the NIO
	// hardware options.
	//
	memset(pIoStat, 0, sizeof(IOSTAT));
	nio_OptionsSize(pIoStat, &m_nOptionsSize);
	if (pIoStat->iostatus != FE_OK)
	{
		m_pszOptions	= NULL;
		m_nNumOptions	= 0;
		hrRet			= S_FALSE;
	}
	else
	{
		m_pszOptions = new char [m_nOptionsSize];
		if (NULL == m_pszOptions)
		{
			hrRet = S_FALSE;
		}
		else
		{
			// Go get the options...
			//
			memset(m_pszOptions, 0, m_nOptionsSize);
			memset(pIoStat, 0, sizeof(IOSTAT));
			nio_EnumOptions(pIoStat, &m_nNumOptions, &m_nOptionsSize, m_pszOptions);
			if (pIoStat->iostatus != FE_OK)
			{
				delete [] m_pszOptions;
				m_pszOptions	= NULL;
				m_nNumOptions	= 0;
				hrRet			= S_FALSE;
			}
			else
			{
				// OK, now we have a buffer containing all of the datatype strings,
				// so let's get the VARTYPEs they correspond to. This will tell us what
				// datatypes the driver supports.
				//
				m_pvtOptionValues = new VARTYPE [m_nNumOptions];
				if (NULL == m_pvtOptionValues)
				{
					delete [] m_pszOptions;
					m_pszOptions = NULL;
				}
				else
				{
					CString	szOption;
					char	*pszOption	= m_pszOptions;
					int		nLength		= 0;
					IOVSPEC	Iov,
							*pIov = &Iov;
					IOREC	IoRec;
					EGUREC	Egu,
							*pEgu = &Egu;
					VARTYPE vDataType;

					Iov.iorec = &IoRec;
					for (int x = 0; x < m_nNumOptions; x++)
					{
						szOption = pszOption;
						nLength = szOption.GetLength();
						pszOption += (++nLength);

						memset(pIoStat, 0, sizeof(IOSTAT));
						memset(&IoRec, 0, sizeof(IOREC));

						nio_popt(pIoStat, pIov, pEgu, szOption.GetBuffer(nLength));
						szOption.ReleaseBuffer();

						vDataType = (VARTYPE)(pIov->iorec->opt & 0x0000FFFF);

						// Signed datatype returns the HI bit set to differciate between
						// signed and unsigned short requested datatype, so clear the
						// HI bit.
						//
						if ((unsigned short)(VT_I2 | 0x8000) == (unsigned short)vDataType)
						{
							vDataType = vDataType & 0x7FFF;
						}

						m_pvtOptionValues[x] = vDataType;
					}
				}
			}
		}
	}

	// Get a pointer to the driver's OLE Automation interface
	//
	if (FAILED(hr = CoCreateInstance(CLSID_OPCHLLServer, 
									 NULL, 
									 CLSCTX_LOCAL_SERVER,
									 IID_IDriver, 
									 (LPVOID *)&this->m_pIDriver)))
	{
		return E_FAIL;
	}

	// Get a pointer to the driver's message object
	//
	if (FAILED(hr = m_pIDriver->QueryInterface(IID_IDriverMessage,
									 (void **)&m_pIDriverMessage)))
	{
		m_pIDriverMessage = NULL;
	}

	// Get a pointer to the driver's OPC connections handling object
	//
	if (FAILED(hr = m_pIDriver->QueryInterface(IID_IOPCConnections,
									 (void **)&this->m_pIOpcConnections)))
	{
		SendMessageToDriver("Unable to obtain OPC connections interface", MSG_WARNING);
		m_pIOpcConnections = NULL;
	}
	else
	{
		long lRef = 0L;
		if (FAILED(hr = m_pIOpcConnections->PutOpcRef(&lRef)))
		{
			SendMessageToDriver("Unable to log OPC connection", MSG_WARNING);
		}
	}

	// Start up the driver
	//
	m_pIDriver->Start();

	return hrRet;
}


////////////////////////////////////////////////////////////////
// IsDataTypeSupported()
//
// Determines if the driver supports a given datatype
//
////////////////////////////////////////////////////////////////
BOOL COPCDrvServer::IsDataTypeSupported(VARTYPE vtDatatype)
{
	// If something failed in the call to GetDriverInfo(), then
	// we don't know what datatypes are supported, so return TRUE
	// just in case.
	//
	if (NULL == m_pvtOptionValues)
	{
		return TRUE;
	}

	// The server always supports VT_EMPTY, VT_BSTR and VT_BOOL.
	//
	switch(vtDatatype)
	{
	case VT_EMPTY:
	case VT_BSTR:
	case VT_BOOL:
		return TRUE;
		break;
	default:
		break;
	}

	for (int x = 0; x < m_nNumOptions; x++)
	{
		if (vtDatatype == m_pvtOptionValues[x])
		{
			// Found it!
			return TRUE;
		}
	}
	return FALSE;
}


////////////////////////////////////////////////////////////////
// SendMessageToDriver()
//
// Sends a message to the driver's event window
//
////////////////////////////////////////////////////////////////
HRESULT COPCDrvServer::SendMessageToDriver(CString			szMessage,
										   unsigned short	nType)		/*	= MSG_ERROR */
{
	HRESULT	hr = S_FALSE;

	// We need to determine if this is the server object's poll thread or
	// the client's thread that made this call. Then we need to use the
	// correct IDriverMessage interface pointer.
	//
	if ((m_dwPollThreadId != GetCurrentThreadId()) && (m_pIDriverMessage))
	{
		BSTR bMessage = szMessage.AllocSysString();
		if (NULL == bMessage)
		{
			return E_OUTOFMEMORY;
		}

		try
		{
			switch(nType)
			{
			default:
			case MSG_ERROR:
				hr = m_pIDriverMessage->ErrorMessage(bMessage);
				break;

			case MSG_INFO:
				hr = m_pIDriverMessage->InfoMessage(bMessage);
				break;

			case MSG_WARNING:
				hr = m_pIDriverMessage->WarnMessage(bMessage);
				break;

			case MSG_DEBUG:
				hr = m_pIDriverMessage->DebugMessage(bMessage);
				break;
			}
		}
		catch(...)
		{
			hr = E_FAIL;
		}

		SysFreeString(bMessage);
	}
	else if (m_dwPollThreadId == GetCurrentThreadId())
	{
		// This is the poll thread, so unmarshall the interface pointer if
		// needed.
		//
		if ((NULL == m_pIDriverMessageMarshalled) && (m_pIDriverMessageStream))
		{
			hr = CoGetInterfaceAndReleaseStream(m_pIDriverMessageStream,
												IID_IDriverMessage, 
												(LPVOID *)&m_pIDriverMessageMarshalled);
			if (FAILED(hr))
			{
				m_pIDriverMessageMarshalled = NULL;
				m_pIDriverMessageStream = NULL;
				return E_FAIL;
			}
		}

		if (m_pIDriverMessageMarshalled)
		{
			BSTR bMessage = szMessage.AllocSysString();
			if (NULL == bMessage)
			{
				return E_OUTOFMEMORY;
			}

			try
			{
				switch(nType)
				{
				default:
				case MSG_ERROR:
					hr = m_pIDriverMessageMarshalled->ErrorMessage(bMessage);
					break;

				case MSG_INFO:
					hr = m_pIDriverMessageMarshalled->InfoMessage(bMessage);
					break;

				case MSG_WARNING:
					hr = m_pIDriverMessageMarshalled->WarnMessage(bMessage);
					break;

				case MSG_DEBUG:
					hr = m_pIDriverMessageMarshalled->DebugMessage(bMessage);
					break;
				}
			}
			catch(...)
			{
				hr = E_FAIL;
			}

			SysFreeString(bMessage);
		}
	}
	return hr;
}


////////////////////////////////////////////////////////////////
// PollThread()
//
// Provides the thread for the "polling engine" used to update
// the server object's groups and items.
//
////////////////////////////////////////////////////////////////
UINT __stdcall COPCDrvServer::PollThread(void *pParam)
{
	COPCDrvServer	*pThis = (COPCDrvServer *)pParam;


	// Initialize the COM libraries for this thread.
	//
	if (FAILED(CoInitializeEx (NULL, COINIT_APARTMENTTHREADED)))
	{
		LogEventMessage(TEXT("Fatal Error. Unable to initialize COM for OPC server poll thread"),
						g_tszAcronym,
						3);
		return 1;
	}

	// Modify the thread priority to match the definable registry settings.
	//
	if (!ChangeDriverThreadPriority(g_dwServerThreadPriority))
	{
		LogEventMessage(TEXT("Unable to change OPC server poll thread priority"),
						g_tszAcronym,
						3);
	}

	// Get the Id of this thread.
	//
	pThis->m_dwPollThreadId = GetCurrentThreadId();

	// Continue to update the server until it is time to shutdown.
	//
	while(pThis->m_bKeepRunning)
	{
		Sleep(g_dwWaitPeriod);
		pThis->UpdateDataCache(GetTickCount() - pThis->m_dwLastTickCount);
		pThis->m_dwLastTickCount = GetTickCount();
	}

	// If we have any marshalled COM interfaces, release them
	//
	try
	{
		if (pThis->m_pIDriverMessageMarshalled)
		{
			pThis->m_pIDriverMessageMarshalled->Release();
			pThis->m_pIDriverMessageMarshalled = NULL;
		}
	}
	catch(...)
	{
		pThis->m_pIDriverMessageMarshalled = NULL;
	}

	// Unitialize the COM libraries and return.
	//
	CoUninitialize();
	_endthreadex(0);
	return 0;
}



⌨️ 快捷键说明

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