📄 opcdrvserver.cpp
字号:
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 + -