www.pudn.com > OPC_VC++.rar > IADVSINK.CPP


/* 
 * IADVSINK.CPP 
 * Data Object User Chapter 10 
 * 
 * Implementation of an object with IAdviseSink. 
 * 
 * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved 
 * 
 * Kraig Brockschmidt, Microsoft 
 * Internet  :  kraigb@microsoft.com 
 * Compuserve:  >INTERNET:kraigb@microsoft.com 
 */ 
 
#include "stdafx.h" 
#include "resource.h" 
#include  
 
#include "OPCSample_cppDlg.h" 
 
#define PRINT_MESSAGE {CString cs, cs1;\ 
     cs1.Format("%s",__LINE__);\ 
      AfxFormatString2(cs, IDS_ERROR_MESSAGE, (LPCSTR)cs1, __FILE__);\ 
      MessageBox(NULL, "", cs, MB_OK);} 
 
extern COPCSample_cppDlg* theDlg; 
 
/* 
 * CAdviseSink::CAdviseSink 
 * CAdviseSink::~CAdviseSink 
 * 
 * Parameters (Constructor): 
 *  pApp            PAPP to the application 
 * 
 */ 
 
CAdviseSink::CAdviseSink() 
    { 
    m_cRef=0; 
    return; 
    } 
 
CAdviseSink::~CAdviseSink(void) 
    { 
    return; 
    } 
 
/* 
 * CAdviseSink::QueryInterface 
 * CAdviseSink::AddRef 
 * CAdviseSink::Release 
 * 
 * Purpose: 
 *  IUnknown members for CAdviseSink object. 
 */ 
 
STDMETHODIMP CAdviseSink::QueryInterface(REFIID riid, void** ppv) 
    { 
    *ppv=NULL; 
 
    if (IID_IUnknown==riid || IID_IAdviseSink==riid) 
        *ppv=this; 
 
    if (NULL!=*ppv) 
        { 
        ((LPUNKNOWN)*ppv)->AddRef(); 
        return NOERROR; 
        } 
 
    return ResultFromScode(E_NOINTERFACE); 
    } 
 
 
STDMETHODIMP_(ULONG) CAdviseSink::AddRef(void) 
    { 
    return ++m_cRef; 
    } 
 
 
STDMETHODIMP_(ULONG) CAdviseSink::Release(void) 
    { 
    if (0!=--m_cRef) 
        return m_cRef; 
 
    delete this; 
    return 0; 
    } 
 
 
 
/* 
 * CAdviseSink::OnDataChange 
 * 
 * Purpose: 
 *  Notifes the advise sink that data changed in a data object. 
 *  On this message you may request a new data rendering and update 
 *  your displays as necessary.  Any data sent to this function is 
 *  owned by the caller, not by this advise sink. 
 * 
 *  All Advise Sink methods are asynchronous and therefore we 
 *  should attempt no synchronous calls from within them to an EXE 
 *  object.  If we do, we'll get RPC_E_CALLREJECTED. 
 * 
 * Parameters: 
 *  pFEIn           LPFORMATETC describing format that changed 
 *  pSTM            LPSTGMEDIUM providing the medium in which the 
 *                  data is provided. 
 * 
 * Return Value: 
 *  None 
 */ 
 
 
STDMETHODIMP_(void) CAdviseSink::OnDataChange(LPFORMATETC pFE 
    , LPSTGMEDIUM pSTM) 
{ 
  int iMode=0; 
  // Verify the format follows the OPC spec 
  if( TYMED_HGLOBAL != pFE->tymed ) 
  { 
    return; 
  } 
  if( pSTM->hGlobal == 0 ) 
  { 
    return; 
  } 
  if( OPCSTMFORMATWRITECOMPLETE != pFE->cfFormat )  // ignore write status notification 
  { 
#ifdef DATATIMEFORMAT 
    if( OPCSTMFORMATDATATIME != pFE->cfFormat )  // ignore write status notification 
#else 
      if( OPCSTMFORMATDATA != pFE->cfFormat )  // ignore write status notification 
#endif // DATATIMEFORMAT 
      { 
        return; 
      } 
  } else 
  { 
    iMode=OPCSTMFORMATWRITECOMPLETE; 
  } 
   
  // It must be a data advise 
  const BYTE* buffer = (BYTE*)GlobalLock( pSTM->hGlobal ); 
  if( !buffer ) 
  { 
    return; 
  } 
   
  const OPCGROUPHEADER* pHeader = (OPCGROUPHEADER*)buffer; 
  // check pHeader->hClientGroup 
  // pHeader->dwTransactionID 
  // pHeader->hrStatus 
  int offset = sizeof(OPCGROUPHEADER); 
  // for each item in the data stream, get the value and  
  if (iMode==(int)OPCSTMFORMATWRITECOMPLETE) 
  { 
    if (!pHeader->dwTransactionID) 
    { 
      //error 
    } 
    if (pHeader->dwItemCount>200) 
    { 
      //error 
    } 
     
    for( DWORD index=0; indexdwItemCount; index++, offset += sizeof(OPCITEMHEADERWRITE) ) 
    { 
      const OPCITEMHEADERWRITE* pItemHeader = (OPCITEMHEADERWRITE*)&buffer[offset]; 
      if ( pItemHeader->dwError != S_OK) 
      { 
        Item* pItem = (Item*)pItemHeader->hClient; 
        if (pItem) 
        { 
          pItem->dwLastError = pItemHeader->dwError; 
          pItem->boActual = TRUE; 
        } else 
        { 
          // DEBUG BREAK 
          pItem=pItem; 
        } 
      }// else 
      // pItem->boActual = TRUE; 
    } 
  } else  
  { 
#ifdef DATATIMEFORMAT 
    for( DWORD index=0; indexdwItemCount; index++, offset += sizeof(OPCITEMHEADER1) ) 
    { 
      const OPCITEMHEADER1* pItemHeader = (OPCITEMHEADER1*)&buffer[offset]; 
#else 
      for( DWORD index=0; indexdwItemCount; index++, offset += sizeof(OPCITEMHEADER2) ) 
      { 
        const OPCITEMHEADER2* pItemHeader = (OPCITEMHEADER2*)&buffer[offset]; 
#endif // DATATIMEFORMAT 
         
        VARIANT* pValue = (VARIANT*)&buffer[pItemHeader->dwValueOffset]; 
        // Strings and arrays are packed in the stream  
        // requiring unpacking 
        if( pValue->vt == VT_BSTR ) 
        { 
          pValue->bstrVal = (BSTR)((BYTE*)pValue + sizeof(VARIANT) + sizeof(DWORD)); 
        } 
        else if( (pValue->vt & VT_ARRAY) == VT_ARRAY ) 
        { 
          pValue->parray = (SAFEARRAY*)((BYTE*)pValue + sizeof(VARIANT)); 
          pValue->parray->pvData = ((BYTE*)pValue->parray + sizeof(SAFEARRAY)); 
        } 
        Item* pItem = (Item*)pItemHeader->hClient; 
        pItem->value = pValue; 
        pItem->quality = pItemHeader->wQuality; 
        pItem->boActual = TRUE; 
      } 
    } 
    GlobalUnlock( pSTM->hGlobal ); 
     
    return; 
  } 
 
 
 
 
/* 
 * CAdviseSink::OnViewChange 
 * CAdviseSink::OnRename 
 * CAdviseSink::OnSave 
 * CAdviseSink::OnClose 
 * 
 * Unimplemented members 
 */ 
 
STDMETHODIMP_(void) CAdviseSink::OnViewChange(DWORD dwAspect 
    , LONG lindex) 
    { 
    return; 
    } 
 
STDMETHODIMP_(void) CAdviseSink::OnRename(LPMONIKER pmk) 
    { 
    return; 
    } 
 
STDMETHODIMP_(void) CAdviseSink::OnSave(void) 
    { 
    return; 
    } 
 
STDMETHODIMP_(void) CAdviseSink::OnClose(void) 
    { 
    return; 
    }