📄 opcdrvgroupdo.cpp
字号:
int vsize = 0;
VARIANT vTemp;
VariantInit(&vTemp);
for (j = 0; j < nCount; j++)
{
// Get serverhandle of items to send
// (they were in use a millisecond ago and are assumed to be still)
//
OPCHandle = ItemHandleList[j];
pItem = GetItemPtr(OPCHandle);
// Get the basic ItemHeader info
//
pItem->GetValue(dwSource,
&vTemp,
&pItemHdr1->wQuality,
&pItemHdr1->ftTimeStampItem); // with time
pItemHdr1->hClient = pItem->GetHandle();
pItemHdr1->dwValueOffset = pcDataPtr - gp;
pItemHdr1->wReserved = 0;
// Plus the variant
// Note that any 'pointer' in the variant will be meaningless
//
vsize = OPCVariantPack(pcDataPtr, &vTemp);
VariantClear(&vTemp);
// If this is an OnDataChange then clear the item changed flag
// else if this is an Async Read then do some special quality handling
//
if(wMask)
{
pItem->ClearChanged(wMask); //with time
}
else
{
// if async read then group must be active
//
if((OPC_DS_CACHE == dwSource) && (!m_bActive))
{
((QUALITY_STATE *)&pItemHdr1->wQuality)->nQuality = QUALITY_BAD;
((QUALITY_STATE *)&pItemHdr1->wQuality)->nSubStatus = SS_OUT_OF_SERVICE;
}
}
// The update the pointers
//
pItemHdr1++;
pcDataPtr += vsize;
}
// And invoke the callback
//
STGMEDIUM stm;
FORMATETC fe;
fe.cfFormat = m_pCImpIDataObject->m_datatime; // with time
fe.ptd = NULL;
fe.dwAspect = DVASPECT_CONTENT;
fe.lindex = -1;
fe.tymed = TYMED_HGLOBAL;
stm.tymed = TYMED_HGLOBAL;
stm.hGlobal = gh;
stm.pUnkForRelease = NULL;
// Save the last update time
//
CoFileTimeNow(&m_pParentServer->m_ftLastUpdate);
// Pull the IAdviseSink interface pointer out of the stream object.
//
if (NULL == m_pdatatimeSink)
{
hr = CoGetInterfaceAndReleaseStream (m_pCImpIDataObject->m_pdatatimeStm,
IID_IAdviseSink,
(LPVOID *)&m_pdatatimeSink);
if (FAILED(hr))
{
return;
}
}
// Call into the IAdviseSink that the client provided with the data.
//
__try
{
m_pdatatimeSink->OnDataChange(&fe, &stm);
}
__finally
{
// And free the storage
//
GlobalFree(gh);
}
}
////////////////////////////////////////////////////////////////
// COPCDrvGroup::SendStream() (Without Time)
//
// @desc This function is used to build the stream for OnDataChange and also
// for async operations such as Read and Refresh
// The two cases are 'almost' the same except for
// a small bit of 'mask' and quality logic as you can see below
//
// Create the Stream which consists of:
// GroupHeader
// ItemHeaders
// Variants and Related Data.
//
// @parm IN int | nCount | Count of items to send
// @parm IN OPCHANDLE * | ItemHandleList| Item handle list
// @parm IN DWORD | dwDataSize | Data size
// @parm IN WORD | wMask | Mask to clear
// @parm IN DWORD | tid | Transaction ID
// @parm IN OPTIONAL OPCDATASOURCE | dwSource | Data source (cache or device)
//
// @retval void
//
// @devnote We use exception handling around the call to OnDataChange()
// since this is an open architecture and we have no control
// over the client's implementation. We want to make sure we
// don't crash.
//
////////////////////////////////////////////////////////////////
void COPCDrvGroup::SendStream(int nCount,
OPCHANDLE *ItemHandleList,
DWORD dwDataSize,
WORD wMask,
DWORD tid,
OPCDATASOURCE dwSource) /* = OPC_DS_DEVICE */
{
int j,
nHdrSize,
nTotalSize;
OPCHANDLE OPCHandle;
HRESULT hr;
// Allocate the Data Stream
//
nHdrSize = sizeof(OPCGROUPHEADER) + nCount * sizeof(OPCITEMHEADER2); // without time
nTotalSize = nHdrSize + dwDataSize;
char * gp;
HGLOBAL gh;
gh = GlobalAlloc(GMEM_FIXED, nTotalSize);
if(NULL == gh)
{
// If no memory, For now we just give up and return;
// But a better error handler would be nice
//
return;
}
gp = (char*)GlobalLock(gh);
OPCGROUPHEADER *pGrpPtr;
OPCITEMHEADER2 *pItemHdr1; // Without Time
char *pcDataPtr;
pGrpPtr = (OPCGROUPHEADER *) gp;
pItemHdr1 = (OPCITEMHEADER2 *) (gp + sizeof(OPCGROUPHEADER)); // without Time
pcDataPtr = gp + nHdrSize;
// Fill in the Group header
//
pGrpPtr->dwSize = nTotalSize;
pGrpPtr->dwItemCount = nCount;
pGrpPtr->hClientGroup = m_ClientGroupHandle;
pGrpPtr->hrStatus = S_OK;
pGrpPtr->dwTransactionID = tid;
// Now fill in the Item Information
//
COPCDrvItem *pItem = NULL;
int vsize = 0;
VARIANT vTemp;
VariantInit(&vTemp);
for (j = 0; j < nCount; j++)
{
// Get serverhandle of items to send
// (they were in use a millisecond ago and are assumed to be still)
// We should be in a critical seciton here
//
OPCHandle = ItemHandleList[j];
pItem = GetItemPtr(OPCHandle);
// Get the basic ItemHeader info
//
pItem->GetValue(dwSource,
&vTemp,
&pItemHdr1->wQuality,
NULL); // without time
pItemHdr1->hClient = pItem->GetHandle();
pItemHdr1->dwValueOffset = pcDataPtr - gp;
pItemHdr1->wReserved = 0;
// Plus the variant
// Note that any 'pointer' in the variant will be meaningless
//
vsize = OPCVariantPack(pcDataPtr, &vTemp);
VariantClear(&vTemp);
// If this is an OnDataChange then clear the item changed flag
// else if this is an Async Read then do some special quality handling
//
if(wMask)
{
pItem->ClearChanged(wMask); // without time
}
else
{
// If async read from cache then group must be active
//
if((OPC_DS_CACHE == dwSource) && (!m_bActive))
{
((QUALITY_STATE *)&pItemHdr1->wQuality)->nQuality = QUALITY_BAD;
((QUALITY_STATE *)&pItemHdr1->wQuality)->nSubStatus = SS_OUT_OF_SERVICE;
}
}
// The update the pointers
//
pItemHdr1++;
pcDataPtr += vsize;
}
// And invoke the callback
//
STGMEDIUM stm;
FORMATETC fe;
fe.cfFormat = m_pCImpIDataObject->m_data; // without time
fe.ptd = NULL;
fe.dwAspect = DVASPECT_CONTENT;
fe.lindex = -1;
fe.tymed = TYMED_HGLOBAL;
stm.tymed = TYMED_HGLOBAL;
stm.hGlobal = gh;
stm.pUnkForRelease = NULL;
// Save the last update time
//
CoFileTimeNow(&m_pParentServer->m_ftLastUpdate);
// Pull the IAdviseSink interface pointer out of the stream object.
//
if (NULL == m_pdataSink)
{
hr = CoGetInterfaceAndReleaseStream (m_pCImpIDataObject->m_pdataStm,
IID_IAdviseSink,
(LPVOID *)&m_pdataSink);
if (FAILED(hr))
{
return;
}
}
// Call into the IAdviseSink that the client provided with the data.
//
__try
{
m_pdataSink->OnDataChange(&fe, &stm); // without time
}
__finally
{
// And free the storage
//
GlobalFree(gh);
}
}
////////////////////////////////////////////////////////////////
// COPCDrvGroup::SendWriteStream()
//
// @desc This function is used to build the stream for OnWriteComplete
//
// Create the Stream which consists of:
// GroupHeader
// ItemHeaders
//
// @parm IN int | nCount | Count of items to send
// @parm IN OPCHANDLE * | ItemHandleList| Item handle list
// @parm IN DWORD | tid | Transaction ID
//
// @retval void
//
// @devnote We use exception handling around the call to OnDataChange()
// since this is an open architecture and we have no control
// over the client's implementation. We want to make sure we
// don't crash.
//
////////////////////////////////////////////////////////////////
void COPCDrvGroup::SendWriteStream(int nCount,
OPCHANDLE *ItemHandleList,
DWORD tid)
{
int j,
nHdrSize,
nTotalSize;
OPCHANDLE OPCHandle;
COPCDrvItem *pItem;
// Allocate the Data Stream
//
nHdrSize = sizeof(OPCGROUPHEADERWRITE) + nCount * sizeof(OPCITEMHEADERWRITE);
nTotalSize = nHdrSize ;
char * gp;
HGLOBAL gh;
gh = GlobalAlloc(GMEM_FIXED, nTotalSize);
if(NULL == gh)
{
// If no memory, For now we just give up and return;
// But a better error handler would be nice
//
return;
}
gp = (char *)GlobalLock(gh);
OPCGROUPHEADERWRITE *pGrpPtr;
OPCITEMHEADERWRITE *pItemHdr1;
pGrpPtr = (OPCGROUPHEADERWRITE *) gp;
pItemHdr1 = (OPCITEMHEADERWRITE *) (gp + sizeof(OPCGROUPHEADERWRITE));
// Fill in the Group Write header
//
pGrpPtr->dwItemCount = nCount;
pGrpPtr->hClientGroup = m_ClientGroupHandle;
pGrpPtr->dwTransactionID = tid;
pGrpPtr->hrStatus = S_OK;
// Now fill in the Item Information
//
for (j = 0; j < nCount; j++)
{
// Get serverhandle of items to send
// We are be in a critical seciton here
//
OPCHandle = ItemHandleList[j];
pItem = GetItemPtr(OPCHandle);
// Get the ItemHeader info
//
pItem->CheckDeviceWrite(&pItemHdr1->dwError);
pItemHdr1->hClient = pItem->GetHandle();
// The update the pointers
//
pItemHdr1++;
}
// And invoke the callback
//
STGMEDIUM stm;
FORMATETC fe;
fe.cfFormat = m_pCImpIDataObject->m_write;
fe.ptd = NULL;
fe.dwAspect = DVASPECT_CONTENT;
fe.lindex = -1;
fe.tymed = TYMED_HGLOBAL;
stm.tymed = TYMED_HGLOBAL;
stm.hGlobal = gh;
stm.pUnkForRelease = NULL;
// Save the last update time
//
CoFileTimeNow(&m_pParentServer->m_ftLastUpdate);
if (NULL == m_pwriteSink)
{
HRESULT hr = CoGetInterfaceAndReleaseStream(m_pCImpIDataObject->m_pwriteStm,
IID_IAdviseSink,
(LPVOID *)&m_pwriteSink);
if (FAILED(hr))
{
return;
}
}
// Call into the IAdviseSink that the client provided with the data.
//
__try
{
m_pwriteSink->OnDataChange(&fe, &stm);
}
__finally
{
// And free the storage
//
GlobalFree(gh);
}
}
////////////////////////////////////////////////////////////////
// COPCDrvGroup::ComputeSize()
//
// @desc This function is used to compute the size of the HGLOBAL
// (a.k.a. 'the stream') needed to contain the OnDataChange
// info for IAdviseSink
//
// @parm IN int | nCount | Number of items
// @parm IN OPCHANDLE * | HandleList | List of item handles
//
// @retval long | Size or data in bytes
//
////////////////////////////////////////////////////////////////
long COPCDrvGroup::ComputeSize(int nCount,
OPCHANDLE *HandleList)
{
long lDataSize = 0L;
for(int i = 0; i < nCount; i++)
{
lDataSize += GetItemPtr(HandleList[i])->GetDataSize();
}
return lDataSize;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -