123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581 |
- #include "stdAfx.h"
- #include "LibApp.h"
- #include "LibOPC.h"
- #include "opcda_i.h"
- #include <comdef.h>
- #include ".\stoneu_opcc.h"
- inline void EnableMemLeakCheck()
- {
- _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
- }
- //#ifdef _DEBUG
- //#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
- //#endif
- const int _OPC_DUPLICATE_GROUP_NAME = -101 ;
- const int _OPC_INVALID_OBJECT = -102 ;
- const int _OPC_TOO_MANY_ITEMS = -103 ;
- const int _OPC_INVALID_GROUP_NAME = -104 ;
- const int _OPC_SERVER_NOT_CONNECTED = -105 ;
- // The OPC data formats
- UINT OPCSTMFORMATDATA = RegisterClipboardFormat(_T("OPCSTMFORMATDATA"));
- UINT OPCSTMFORMATDATATIME = RegisterClipboardFormat(_T("OPCSTMFORMATDATATIME"));
- UINT OPCSTMFORMATWRITECOMPLETE = RegisterClipboardFormat(_T("OPCSTMFORMATWRITECOMPLETE"));
- ///////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
- 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; index<pHeader->dwItemCount; 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; index<pHeader->dwItemCount; index++, offset += sizeof(OPCITEMHEADER1) )
- {
- const OPCITEMHEADER1* pItemHeader = (OPCITEMHEADER1*)&buffer[offset];
- #else
- for( DWORD index=0; index<pHeader->dwItemCount; 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;
- }
- CAppServer::CAppServer() :
- m_nGroupNo(-1),
- m_nTotalGroups(0),
- m_GroupHandle (0)
- {
- for (int i=0; i<_OPC_MAX_GROUP; i++)
- {
- GroupNumber[i].m_szGrpName[0] = L'\0' ;
- GroupNumber[i].m_GroupHandle = 0 ;
- GroupNumber[i].m_NoOfItems = 0 ;
- GroupNumber[i].m_nGroupNo = -1 ;
- }
- _CrtSetBreakAlloc(65);
- pcSink = new CAdviseSink(); // create the advise sink for notifications
- pcSink->AddRef();
- m_nTagCount = 0;
- m_pcItem=new Item[_OPC_MAX_HANDLE];
- }
- ///////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
- CAppServer::~CAppServer()
- {
- m_sTagNameAll.RemoveAll();
- pcSink->Release(); // OLE should clean this up, but may not have time!
- }
- ///////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
- CAppServer::CAppServer(wchar_t* svrName, wchar_t* svrType) :
- m_nGroupNo(-1),
- m_nTotalGroups(0),
- m_GroupHandle (0)
- {
- wcscpy (m_wstrServerName, svrName) ;
- wcscpy (m_wstrServerType, svrType) ;
- for (int i=0; i<_OPC_MAX_GROUP; i++)
- {
- GroupNumber[i].m_szGrpName[0] = L'\0' ;
- GroupNumber[i].m_GroupHandle = 0 ;
- GroupNumber[i].m_NoOfItems = 0 ;
- GroupNumber[i].m_nGroupNo = -1 ;
- }
- }
- ///////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
- CAppServer::CAppServer (const CAppServer &rhs) :
- m_nGroupNo (rhs.m_nGroupNo),
- m_nTotalGroups(rhs.m_nTotalGroups),
- m_GroupHandle (rhs.m_GroupHandle),
- m_pIOPCServer (rhs.m_pIOPCServer),
- m_pIOPCSyncIO (rhs.m_pIOPCSyncIO)
- {
- wcscpy (m_wstrServerName, rhs.m_wstrServerName) ;
- wcscpy (m_wstrServerType, rhs.m_wstrServerType) ;
- for (int i=0; i<_OPC_MAX_GROUP; i++)
- {
- GroupNumber[i] = rhs.GroupNumber[i] ;
- m_pIOPCGroupStateMgt[i] = rhs.m_pIOPCGroupStateMgt[i] ;
- }
- }
- ///////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
- CAppServer& CAppServer::operator=(const CAppServer &rhs)
- {
- m_nGroupNo = rhs.m_nGroupNo ;
- m_nTotalGroups = rhs.m_nTotalGroups ;
- m_GroupHandle = rhs.m_GroupHandle ;
- m_pIOPCServer = rhs.m_pIOPCServer ;
- m_pIOPCSyncIO = rhs.m_pIOPCSyncIO ;
- wcscpy(this->m_wstrServerName, rhs.m_wstrServerName) ;
- wcscpy(this->m_wstrServerType, rhs.m_wstrServerType) ;
- for (int i=0; i<_OPC_MAX_GROUP; i++)
- {
- GroupNumber[i] = rhs.GroupNumber[i] ;
- m_pIOPCGroupStateMgt[i] = rhs.m_pIOPCGroupStateMgt[i] ;
- }
- return *this ;
- }
- ///////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
- HRESULT CAppServer::OPCConnect(wchar_t* svrName, wchar_t* svrType)
- {
- #if 1
- CLSID clsid ;
- COSERVERINFO csvrinfo;
- MULTI_QI queryInterface;
- LPUNKNOWN pUnkn = NULL;
- HRESULT hr ;
- //size_t len = strlen(svrName) + 1;
- //size_t converted = 0;
- //wchar_t *WStr;
- //WStr=(wchar_t*)malloc(len*sizeof(wchar_t));
- //mbstowcs_s(&converted, m_wstrServerName, len, svrName, _TRUNCATE);
- wcscpy (m_wstrServerName, svrName) ;
- wcscpy (m_wstrServerType, svrType) ;
- // Get the Class ID from the Program ID
- // Take note that the server name and type must be wide-character
- hr = CLSIDFromProgID(m_wstrServerType, &clsid );
- if ( FAILED (hr))
- return hr ;
- // Assign GUID of IOPCServer Interface to the MULTI_QI structure
- queryInterface.pIID = &IID_IOPCServer ;
- queryInterface.pItf = NULL ;
- queryInterface.hr = 0 ;
- memset(&csvrinfo, 0, sizeof(COSERVERINFO));
- csvrinfo.pAuthInfo = NULL ;
- // If the server name is blank, assume the server is
- // the Local Server, and set it to NULL
- if (!wcslen(m_wstrServerName))
- csvrinfo.pwszName = NULL ;
- else
- csvrinfo.pwszName = m_wstrServerName ;
- // Create an instance and retrieve the IOPCServer Interface
- hr = ::CoCreateInstanceEx(clsid, NULL, CLSCTX_SERVER, &csvrinfo, 1, &queryInterface);
- m_pIOPCServer = queryInterface.pItf ;
- if( FAILED(hr) || m_pIOPCServer == NULL)
- return hr ;
- queryInterface.pItf->Release() ;
- return hr ;
- #endif
- return 0;
- }
- HRESULT CAppServer::OPCConnect(CString svrName, CString svrType)
- {
- CLSID clsid ;
- COSERVERINFO csvrinfo;
- MULTI_QI queryInterface;
- LPUNKNOWN pUnkn = NULL;
- HRESULT hr ;
- //size_t len = strlen(svrName) + 1;
- //size_t converted = 0;
- //wchar_t *WStr;
- //WStr=(wchar_t*)malloc(len*sizeof(wchar_t));
- //mbstowcs_s(&converted, m_wstrServerName, len, svrName, _TRUNCATE);
- //m_wstrServerName = svrName.AllocSysString();
- MultiByteToWideChar(CP_ACP,0,svrName,-1,m_wstrServerName,256);
- MultiByteToWideChar(CP_ACP,0,svrType,-1,m_wstrServerType,256);
- //wcscpy (m_wstrServerName, svrName) ;
- //wcscpy (m_wstrServerType, svrType) ;
- // Get the Class ID from the Program ID
- // Take note that the server name and type must be wide-character
- hr = CLSIDFromProgID(m_wstrServerType, &clsid );
- if ( FAILED (hr))
- return hr ;
- // Assign GUID of IOPCServer Interface to the MULTI_QI structure
- memset(&queryInterface, 0, sizeof(queryInterface));
- queryInterface.pIID = &IID_IUnknown;//&IID_IOPCServer ;
- //queryInterface.pItf = NULL ;
- //queryInterface.hr = 0 ;
- memset(&csvrinfo, 0, sizeof(COSERVERINFO));
- csvrinfo.pAuthInfo = NULL ;
- // If the server name is blank, assume the server is
- // the Local Server, and set it to NULL
- if (!wcslen(m_wstrServerName))
- csvrinfo.pwszName = NULL ;
- else
- csvrinfo.pwszName = m_wstrServerName ;
- // Create an instance and retrieve the IOPCServer Interface
- hr = ::CoCreateInstanceEx(clsid, NULL, CLSCTX_REMOTE_SERVER, &csvrinfo, 1, &queryInterface);
- //HRESULT hRet=CoCreateInstanceEx(OPCCLSID,NULL,CLSCTX_REMOTE_SERVER,&ServerInfo,1,qi);
- //hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IUnknown, (LPVOID *)&pUnkn);
- m_pIOPCServer = queryInterface.pItf ;
- if( FAILED(hr) || m_pIOPCServer == NULL)
- return hr ;
- queryInterface.pItf->Release() ;
- return hr ;
- }
- ///////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////
- HRESULT CAppServer::OPCConnect()
- {
- CLSID clsid ;
- COSERVERINFO csvrinfo;
- MULTI_QI queryInterface;
- LPUNKNOWN pUnkn = NULL;
- HRESULT hr ;
- // Get the Class ID from the Program ID
- // Take note that the server name and type must be wide-character
- hr = CLSIDFromProgID(m_wstrServerType, &clsid );
- if ( FAILED (hr))
- return hr ;
- // Assign GUID of IOPCServer Interface to the MULTI_QI structure
- queryInterface.pIID = &IID_IOPCServer ;
- queryInterface.pItf = NULL ;
- queryInterface.hr = 0 ;
- memset(&csvrinfo, 0, sizeof(COSERVERINFO));
- csvrinfo.pAuthInfo = NULL ;
- // If the server name is blank, assume the server is
- // the Local Server, and set it to NULL
- if (!wcslen(m_wstrServerName))
- csvrinfo.pwszName = NULL ;
- else
- csvrinfo.pwszName = m_wstrServerName ;
- // Create an instance and retrieve the IOPCServer Interface
- hr = ::CoCreateInstanceEx(clsid, NULL, CLSCTX_SERVER, &csvrinfo, 1, &queryInterface);
- m_pIOPCServer = queryInterface.pItf ;
- if( FAILED(hr) || m_pIOPCServer == NULL)
- return hr ;
- queryInterface.pItf->Release() ;
- return hr ;
- }
- ///////////////////////////////////////////////////////////////////////////
- // This Method adds a group to the OPC Server
- // Note that when a group is added, the group becomes the
- // current default group. This means that all subsequent operation
- // i.e. addition of tags, reading or writing of tags will use this group.
- // If operation on a different group is to be carried out, then the group
- // must be changed first by using the method, OPCChangeGroup().
- ///////////////////////////////////////////////////////////////////////////
- HRESULT CAppServer::OPCAddGroup(LPWSTR szGrpName)
- {
- HRESULT hr ;
- bool bActive = TRUE ;
- OPCHANDLE hClientGroupHandle = 1000 ;
- DWORD dwLCID = 0 ;
- DWORD dwRtnUpdateRate ;
- long *pTimeBias = NULL ;
- DWORD dwReqUpdateRate = 1000 ;
- float pPercentDeadband = 0.0;
- CGroup GrpNum ;
- // _wcsupr(szGrpName) ; // Convert all Uppercase for easy comparison
- if (AddGroupName (szGrpName, GrpNum))
- return _OPC_DUPLICATE_GROUP_NAME ;
- m_nGroupNo = GrpNum.m_nGroupNo ;
- // Add a group
- hr = m_pIOPCServer->AddGroup( szGrpName, TRUE, 1000, //szGrpName, TRUE, 1000,
- 1324, NULL, &pPercentDeadband, //hClientGroupHandle, NULL, NULL,
- dwLCID, &m_GroupHandle, &dwRtnUpdateRate,
- IID_IOPCGroupStateMgt,
- reinterpret_cast<IUnknown**> (&m_pIOPCGroupStateMgt[m_nGroupNo]));
- if (FAILED (hr))
- {
- GroupNumber[m_nGroupNo].m_szGrpName[0] = L'\0' ;
- m_pIOPCGroupStateMgt[m_nGroupNo].Release() ;
- return hr ;
- }
- m_pIOPCGroupStateMgt[m_nGroupNo]->QueryInterface(IID_IDataObject,(LPVOID*)&m_pIOPCDataObject);
- // data advise format
- FORMATETC formatEtc ;
- #ifdef DATATIMEFORMAT
- formatEtc.cfFormat = OPCSTMFORMATDATATIME ;
- #else
- formatEtc.cfFormat = OPCSTMFORMATDATA ;
- #endif // DATATIMEFORMAT
- formatEtc.tymed = TYMED_HGLOBAL;
- formatEtc.ptd = NULL;
- formatEtc.dwAspect = DVASPECT_CONTENT;
- formatEtc.lindex = -1;
- hr = m_pIOPCDataObject->DAdvise(&formatEtc,
- 0, // ADVF flag
- pcSink,
- &dwConnection);
- pcSink->Release();
- GroupNumber[m_nGroupNo].m_GroupHandle = m_GroupHandle ;
- m_nTotalGroups++ ;
- return hr ;
- }
- ///////////////////////////////////////////////////////////////////////////
- // This Method adds tags to the current group. If tags are to be added
- // to a different group, then the group must be changed first by using
- // OPCChangeGroup() method.
- // ItemIDs is an array of tagnames.
- // ClientHandles is an array of arbitarily assigned integers by the caller.
- // ServerHandles is an array corresponding to the ClientHandles array returned
- // by OPC Server.Use the ServerHandles for all reading or writing of items to
- // the OPC Server. The OPC Server knows only the ServerHandles.
- ///////////////////////////////////////////////////////////////////////////
- HRESULT CAppServer::OPCAddTags (CString * ItemIDs, DWORD NoOfItems, OPCHANDLE ServerHandles[], CResult* pResult)
- {
- HRESULT hr=S_OK ;
- DWORD index ;
- OPCITEMDEF* idef ;
- OPCITEMRESULT* pResults ;
- HRESULT* pErrors ;
- // Assign the variable pItemMgt of type IOPCItemMgt Interface using the
- // smart pointer, CComQIPtr. CComQIPtr will add and release references automatically
- CComQIPtr <IOPCItemMgt, &IID_IOPCItemMgt> pItemMgt (m_pIOPCGroupStateMgt[m_nGroupNo]) ;
- if (!m_pIOPCServer || !m_pIOPCGroupStateMgt[m_nGroupNo] || NoOfItems <= 0)
- return _OPC_INVALID_OBJECT ;
- if (NoOfItems > _OPC_MAX_HANDLE)
- return _OPC_TOO_MANY_ITEMS ;
- // for (DWORD idx=0; idx<NoOfItems; idx++)
- // _wcsupr(ItemIDs[idx]) ; // OPC requuires items to be Uppercase. May not be necessary now.
- GroupNumber[m_nGroupNo].m_NoOfItems += NoOfItems ;
- // create a new OPC Item Definition pointer
- idef = new OPCITEMDEF [NoOfItems] ;
- //Item* pcItem;
- //pcItem = new Item;
- for ( index=0; index<NoOfItems ; index++ )
- {
- m_pcItem[m_nTagCount].quality = 0;
- m_pcItem[m_nTagCount].name = ItemIDs[index];
- idef[index].szItemID = ItemIDs[index].AllocSysString();
- idef[index].bActive = TRUE;
- idef[index].dwBlobSize = 0;
- idef[index].pBlob = NULL;
- idef[index].szAccessPath = NULL;
- idef[index].hClient = (OPCHANDLE)&m_pcItem[m_nTagCount]; // pointer to item is its "handle"
- idef[index].vtRequestedDataType = VT_EMPTY;
- pResult->hClient = idef[index].hClient;
- //delete pcItem;
- }
- //delete pcItem;
- // Add items using the IOPCItemMgt pointer
- hr = pItemMgt->AddItems (NoOfItems, idef, &pResults, &pErrors) ;
- delete []idef;
- if (hr==S_FALSE)
- {
- return hr ;
- }
- else
- {
- pResult->vtCanonicalDataType = pResults->vtCanonicalDataType;
- }
- DWORD setNum = 0 ;
- int nErr = 0 ;
- for (index=0; index<NoOfItems; index++)
- {
- if ( SUCCEEDED(pErrors[index]) )
- {
- ServerHandles[m_nTagCount] = pResults[index].hServer ;
- m_sAddTagName.Add( ItemIDs[index] );
- m_nTagCount++;
- }
- else
- nErr++ ;
- pResult[index].pErrors = pErrors[index] ;
- }
- CoTaskMemFree( pResults );
- CoTaskMemFree( pErrors );
- return hr ;
- }
- ///////////////////////////////////////////////////////////////////////////
- // This Method Read Tags.
- // pValues is a structure of type CItem. See CItem in the header file
- // ServerHandles is the array originally used in the OPCAddTags().
- ///////////////////////////////////////////////////////////////////////////
- HRESULT CAppServer::OPCReadTags (CItem* pValues, DWORD NoOfItems, OPCHANDLE ServerHandles[],int &nErr)
- {
- // Test to see if the Interface is still connected to the server
- if (!CoIsHandlerConnected (m_pIOPCGroupStateMgt[m_nGroupNo]))
- {
- m_pIOPCGroupStateMgt[m_nGroupNo].Release() ;
- }
- OPCITEMSTATE* pItemState;
- HRESULT hr,*pErrors;
- // Assign the variable opcSyncIO of type IOPCSyncIO Interface using the
- // smart pointer, CComQIPtr. CComQIPtr will add and release references automatically
- CComQIPtr<IOPCSyncIO, &IID_IOPCSyncIO> opcSyncIO (m_pIOPCGroupStateMgt[m_nGroupNo]) ;
- if (NoOfItems <= 0 || NoOfItems > _OPC_MAX_HANDLE)
- return _OPC_TOO_MANY_ITEMS ;
- // for (DWORD idx=0; idx<NoOfItems; idx++)
- // _wcsupr(pValues[idx].cName) ;
- // Read the items using the IOPCSyncIO Interface pointer.
- hr = opcSyncIO->Read(OPC_DS_CACHE, NoOfItems,ServerHandles, &pItemState, &pErrors);//ServerHandles
- if( SUCCEEDED(hr) )
- {
- nErr = 0 ;
- for(DWORD index=0; index < NoOfItems; index++) //DWORD index=0;
- {
- //if ( FAILED(pErrors[index]) )
- // nErr++ ;
- //pValues[index].cName = ServerHandles[index].sName;
- //MultiByteToWideChar(CP_ACP,0,ServerHandles[index].sName,-1,pValues[index].cName,256);
- pValues[index].sName = m_sAddTagName[index];
- pValues[index].quality = pItemState[index].wQuality ;
- pValues[index].timestamp = pItemState[index].ftTimeStamp ;
- pValues[index].hClient = pItemState[index].hClient ;
- pValues[index].type = pItemState[index].vDataValue.vt ;
- pValues[index].value.vt = pItemState[index].vDataValue.vt ;
- pValues[index].nResult = pErrors[index] ;
- ReadDataValues(pValues, pItemState, index) ;
- }
- CoTaskMemFree( pItemState );
- CoTaskMemFree( pErrors );
- }
- else
- {
- CoTaskMemFree( pItemState );
- CoTaskMemFree( pErrors );
- }
- // if hr = S_OK, all the data is guarantee to be good.
- // if hr = S_FALSE, there are good and bad data.
- return hr ;
- }
- ///////////////////////////////////////////////////////////////////////////
- // This Method Write Tags.
- // pValues is a structure of type CItem. See CItem in the header file
- // ServerHandles is the array originally used in the OPCAddTags().
- ///////////////////////////////////////////////////////////////////////////
- HRESULT CAppServer::OPCWriteTags(CItem* pValues, DWORD NoOfItems, OPCHANDLE ServerHandles[],int &nErr)
- {
- // Test for connectivity
- if (!CoIsHandlerConnected (m_pIOPCGroupStateMgt[m_nGroupNo]))
- m_pIOPCGroupStateMgt[m_nGroupNo].Release() ;
- HRESULT hr, *pErrors = NULL;
- VARIANT vartype[_OPC_MAX_HANDLE];
- CComQIPtr<IOPCSyncIO, &IID_IOPCSyncIO> opcSyncIO (m_pIOPCGroupStateMgt[m_nGroupNo]) ;
- if (NoOfItems <= 0 || NoOfItems > _OPC_MAX_HANDLE)
- return _OPC_TOO_MANY_ITEMS ;
- for (DWORD idx=0; idx<NoOfItems; idx++)
- {
- // _wcsupr(pValues[idx].cName) ;
- VariantInit(&vartype[idx]);
- //if(pValues[idx].value.vt==VT_BSTR)
- //{
- //vartype[idx].vt=VT_BSTR;
-
- // vartype[idx].vt=VT_LPSTR;
- // _tcscpy(ss,pValues[idx].value.bstrVal);
- //vartype[idx].bstrVal=pValues[idx].value.bstrVal;
- // vartype[idx].pbstrVal=&ss;
- // }else
- // {
- VariantClear(&vartype[idx]);
- if(S_OK!=VariantCopy(&vartype[idx],&(pValues[idx].value)))
- {
- continue;
- }
- //MapStringValToArrayVariant( pValues[0].sName,&(pValues[idx].value),&vartype[idx] );
- //ReadDataValues( &vartype[idx],&(pValues[idx].value),pValues[idx].type );
-
- // }
- //vartype[idx].vt = pValues[idx].value.vt;
- //vartype[idx] = pValues[idx].value;
- }
- // Write the items using the IOPCSyncIO Interface pointer.
- hr = opcSyncIO->Write(NoOfItems, ServerHandles, vartype, &pErrors) ;
-
- if( SUCCEEDED(hr) )
- {
- nErr = 0 ;
- for(DWORD index=0; index < NoOfItems; index++)
- {
- if ( FAILED(pErrors[index]) )
- nErr++ ;
- pValues[index].nResult = pErrors[index] ;
- }
- CoTaskMemFree( pErrors );
- }
- else
- {
- CoTaskMemFree( pErrors );
- }
- return hr ;
- }
- ///////////////////////////////////////////////////////////////////////////
- // Extracts the value corresponding to the vt type. Note, if the value is
- // of type VT_BSTR, don't forget to release the bstrVal that came from the
- // OPC Server. The OPC Server allocates memory for VT_BSTR type. It is the
- // responsibility of the client to release the allocated memory
- ///////////////////////////////////////////////////////////////////////////
- void CAppServer::ReadDataValues(CItem* pValues, OPCITEMSTATE* pItemState, DWORD index)
- {
- switch (pItemState[index].vDataValue.vt)
- {
- case VT_UI1:
- pValues[index].value.bVal = pItemState[index].vDataValue.bVal ;
- break;
- case VT_I2:
- pValues[index].value.iVal = pItemState[index].vDataValue.iVal ;
- break;
- case VT_I4:
- pValues[index].value.lVal = pItemState[index].vDataValue.lVal ;
- break;
- case VT_R4:
- pValues[index].value.fltVal = pItemState[index].vDataValue.fltVal ;
- break;
- case VT_R8:
- pValues[index].value.dblVal = pItemState[index].vDataValue.dblVal ;
- break;
- case VT_BOOL:
- pValues[index].value.boolVal = pItemState[index].vDataValue.boolVal ;
- break;
- case VT_BSTR:
- //SysFreString
- //wcscpy(pValues[index].value.bstrVal, pItemState[index].vDataValue.bstrVal) ;
- pValues[index].value.bstrVal=SysAllocString(pItemState[index].vDataValue.bstrVal);
- SysFreeString(pItemState[index].vDataValue.bstrVal);
- break;
- case VT_NULL:
- break;
- // Note: VT_CY and VT_DATE are not implemented
- default:
- break;
- }
- }
- void CAppServer::ReadDataValues(VARIANT* pDes, VARIANT* pScr,VARTYPE nType )
- {
- switch (nType)
- {
- case VT_UI1:
- pDes->bVal = pScr->bVal ;
- break;
- case VT_I2:
- pDes->iVal = pScr->iVal ;
- break;
- case VT_I4:
- pDes->lVal = pScr->lVal ;
- break;
- case VT_R4:
- pDes->fltVal = pScr->fltVal ;
- break;
- case VT_R8:
- pDes->dblVal = pScr->dblVal ;
- break;
- case VT_BOOL:
- pDes->boolVal = pScr->boolVal ;
- break;
- case VT_BSTR:
- //SysFreString
- //wcscpy(pDes->.value.bstrVal, pScr->vDataValue.bstrVal) ;
- pDes->bstrVal=SysAllocString(pScr->bstrVal);
- SysFreeString(pScr->bstrVal);
- break;
- case VT_NULL:
- break;
- // Note: VT_CY and VT_DATE are not implemented
- default:
- break;
- }
- }
- bool CAppServer::MapStringValToArrayVariant (CString &strValue, VARIANT *pvtSrc, VARIANT *pvtDst)
- {
- // Source variant must not be empty:
- if (pvtSrc->vt == VT_EMPTY)
- return (false);
- ASSERT (pvtSrc != NULL);
- ASSERT (pvtDst != NULL);
- ASSERT (pvtSrc->vt & VT_ARRAY);
- // Source variant must contain array data:
- if (!pvtSrc->parray)
- return (false);
- int cnRows = 0;
- int cnCols = 0;
- TCHAR szValue [260];
- // Create a local copy of input string:
- lstrcpyn (szValue, strValue, (sizeof (szValue) / sizeof (TCHAR)) - sizeof (TCHAR));
- // Set number of rows and columns for this array:
-
- // 1-D array:
- if (pvtSrc->parray->cDims == 1)
- {
- cnRows = 1;
- cnCols = pvtSrc->parray->rgsabound [0].cElements;
- }
- // 2-D array:
- else if (pvtSrc->parray->cDims == 2)
- {
- cnRows = pvtSrc->parray->rgsabound [0].cElements;
- cnCols = pvtSrc->parray->rgsabound [1].cElements;
- }
- // Do not support more than 2 dimensions:
- else
- {
- ASSERT (FALSE);
- return (false);
- }
- // Initialize destination array:
- VariantInit (pvtDst);
- // Set destination array type:
- pvtDst->vt = pvtSrc->vt;
- // Allocate memory for destination array:
- pvtDst->parray = SafeArrayCreate (pvtSrc->vt & ~VT_ARRAY,
- pvtSrc->parray->cDims, pvtSrc->parray->rgsabound);
- // Copy data to destination array:
- VariantCopy (pvtDst, pvtSrc);
- // Overwrite fields with data:
- int nIndex = 0;
- GETARRELEMRET eRet;
- BYTE HUGEP *pVal = (BYTE *) pvtDst->parray->pvData;
- int cnRowElements = 0;
- // Loop over all array elements:
- for (int i = 0; i < cnRows * cnCols; i++)
- {
- // Create a scratch buffer for parsed array element string:
- TCHAR szBuffer [260];
- // Parse next element in string:
- eRet = GetArrayElement (szValue, &nIndex, szBuffer, 260);
- // If parse resulted in done code, the break out of loop:
- if (eRet == tDone)
- break;
- // If parse resulted in invalid code, return false:
- if (eRet == tInvalid)
- {
- TRACE (_T("OTC: Invalid character parsing array value\r\n"));
- return (false);
- }
- // If parse reslted in overflow code, return false:
- if (eRet == tOverflow)
- {
- TRACE (_T("OTC: Buffer overflow parsing array value\r\n"));
- return (false);
- }
- // If we make it here, we expect to have element or end of row code:
- ASSERT (eRet == tElement || eRet == tEndRow);
- // If element is not NULL string, then overwrite field in destination:
- if (*szBuffer != _T('\0'))
- {
- // Cast string to proper type:
- switch (pvtDst->vt & ~VT_ARRAY)
- {
- case VT_UI1 : *pVal = (BYTE) _ttol (szBuffer); break;
- case VT_I1 : *pVal = (char) _ttol (szBuffer); break;
- case VT_UI2 : *(WORD *)pVal = (WORD) _ttol (szBuffer); break;
- case VT_I2 : *(short *)pVal = (short) _ttol (szBuffer); break;
- case VT_UI4 : *(DWORD *)pVal = (DWORD) _ttol (szBuffer); break;
- case VT_I4 : *(long *)pVal = (long) _ttol (szBuffer); break;
- case VT_R4:
- // Text to float conversions can throw exceptions, so
- // be prepared to handle them:
- try
- {
- #ifdef _UNICODE
- *(float *)pVal = (float) wtof (szBuffer);
- #else
- *(float *)pVal = (float) atof (szBuffer);
- #endif
- }
-
- catch (...)
- {
- *(float *)pVal = 0;
- }
- break;
- case VT_R8:
- // Text to float conversions can throw exceptions, so
- // be prepared to handle them:
- try
- {
- #ifdef _UNICODE
- *(double *)pVal = (double) wtof (szBuffer);
- #else
- *(double *)pVal = (double) atof (szBuffer);
- #endif
- }
-
- catch (...)
- {
- *(double *)pVal = 0;
- }
- break;
- // Unexpected type:
- default:
- ASSERT (FALSE);
- break;
- }
- }
- // Increment destination array pointer to accept next element:
- // If last element in row:
- if (eRet == tEndRow && cnCols > cnRowElements)
- {
- pVal += (pvtDst->parray->cbElements * (cnCols - cnRowElements));
- cnRowElements = 0;
- }
- // Else next element:
- else
- {
- cnRowElements++;
- pVal += pvtDst->parray->cbElements;
- }
- }
- // If we make it here, then return true to indicate success:
- return (true);
- }
- GETARRELEMRET CAppServer::GetArrayElement (LPCTSTR szInBuff, int *pnStart, LPTSTR szOutBuff, int nBuffSize)
- {
- // Initialize some variables:
- TCHAR ch = _T('\r');
- BOOL bLeftBracket = FALSE;
- int cnChars = 0;
-
- GETARRELEMRET eRet = tElement;
- // If we are at the end of the buffer then we're done:
- if (!szInBuff [*pnStart])
- return (tDone);
- // Continue to read characters until we hit the next comma or
- // an EOL (End Of Line - "\n") character:
- while (TRUE)
- {
- // Get the next character, and increment start position for next time:
- ch = szInBuff [(*pnStart)++];
- // If the character is NULL, we are at the end of the record and
- // therefore is nothing left to read. Back up the start position
- // and break out of the loop.
- if (!ch)
- {
- (*pnStart)--;
- break;
- }
- // Trim leading whitespace, if any. If current character is a space,
- // then continue. This will force us to process next character without
- // saving current one (a space) in output buffer.
- if (!cnChars && _istspace (ch))
- continue;
- // Brackets and commas delimit the fields:
- if (ch == _T('['))
- {
- if (bLeftBracket)
- {
- eRet = tInvalid;
- break;
- }
- continue;
- }
- if (ch == _T(']'))
- {
- eRet = tEndRow;
- break;
- }
- if (ch == _T(','))
- break;
- // If we make it here, then the current character is "a keeper".
- // Increment the character counter:
- ++cnChars;
- // Add the current character to the output buffer as long a there
- // is room:
- if (nBuffSize > 1)
- {
- // There is room, so add the current character to the output
- // buffer, and move output buffer pointer to next position.
- *szOutBuff++ = ch;
- // Decrement nBuffSize. When it hits zero we know we have
- // filled the output buffer to capacity.
- --nBuffSize;
- }
- else
- {
- // There is no more room in the output buffer. Set the bOverflow
- // flag, but don't break out of the loop. We want to keep going
- // until we hit a field deleimiter. This will allow us to parse
- // the next field, even though this one is too big to deal with.
- eRet = tOverflow;
- break;
- }
- }
- // Make sure the output string is properly NULL terminated:
- *szOutBuff = 0;
- // Return return code:
- return (eRet);
- }
- ///////////////////////////////////////////////////////////////////////////
- // This Method is used for checking the validity of a group name
- // and returns the appropriate group structure if one is found
- ///////////////////////////////////////////////////////////////////////////
- int CAppServer::CheckGroupName(LPWSTR szGrpName, CGroup &GrpNum)
- {
- // _wcsupr(szGrpName) ;
- for (int indx=0; indx<_OPC_MAX_GROUP; indx++)
- if (!wcscmp (szGrpName, GroupNumber[indx].m_szGrpName))
- {
- GrpNum = GroupNumber[indx] ;
- return FALSE ;
- }
- return TRUE;
- }
- ///////////////////////////////////////////////////////////////////////////
- // This Method adds a new group name to the array. The maximum group
- // is defined in _OPC_MAX_GROUP.
- ///////////////////////////////////////////////////////////////////////////
- int CAppServer::AddGroupName(LPWSTR szGrpName, CGroup &GrpNum)
- {
- // _wcsupr(szGrpName) ;
- for (int indx=0; indx<_OPC_MAX_GROUP; indx++)
- if (!GroupNumber[indx].m_szGrpName[0])
- {
- wcscpy(GroupNumber[indx].m_szGrpName, szGrpName) ;
- GroupNumber[indx].m_nGroupNo = indx ;
- GrpNum = GroupNumber[indx] ;
- break ;
- }
- else
- {
- if (!wcscmp(szGrpName, GroupNumber[indx].m_szGrpName))
- return TRUE ;
- }
- if (indx == _OPC_MAX_GROUP) return TRUE ;
- return FALSE;
- }
- ///////////////////////////////////////////////////////////////////////////
- // This Method is used to change to another group. The new group
- // becomes the default group
- ///////////////////////////////////////////////////////////////////////////
- int CAppServer::OPCChangeGroup(LPWSTR szGrpName)
- {
- // _wcsupr(szGrpName) ;
- for (int indx=0; indx<_OPC_MAX_GROUP; indx++)
- if (!wcscmp(szGrpName, GroupNumber[indx].m_szGrpName))
- {
- m_nGroupNo = GroupNumber[indx].m_nGroupNo ;
- return FALSE ;
- }
- return TRUE ;
- }
- ///////////////////////////////////////////////////////////////////////////
- // This Method is used to remove Items in a specified Group
- ///////////////////////////////////////////////////////////////////////////
- HRESULT CAppServer::OPCRemoveItems (LPWSTR szGrpName, DWORD NoOfItems, OPCHANDLE ServerHandles[], HRESULT pErr[])
- {
- HRESULT hr ;
- CGroup GrpNum ;
- HRESULT *pErrors = 0;
- if (!CheckGroupName(szGrpName, GrpNum))
- {
- if (!CoIsHandlerConnected(m_pIOPCGroupStateMgt[GrpNum.m_nGroupNo]))
- {
- m_pIOPCGroupStateMgt[GrpNum.m_nGroupNo].Release() ;
- return _OPC_SERVER_NOT_CONNECTED ;
- }
- CComQIPtr <IOPCItemMgt, &IID_IOPCItemMgt> pItemMgt (m_pIOPCGroupStateMgt[GrpNum.m_nGroupNo]) ;
- hr = pItemMgt->RemoveItems(NoOfItems, ServerHandles, &pErrors) ;
- if( SUCCEEDED(hr) )
- CoTaskMemFree( pErrors );
- if (FAILED(hr))
- return hr ;
- m_nTagCount = 0;
- GroupNumber[GrpNum.m_nGroupNo].m_NoOfItems=0;
- pItemMgt.Release() ;
- return hr ;
- }
- else
- return _OPC_INVALID_GROUP_NAME ;
- }
- ///////////////////////////////////////////////////////////////////////////
- // This Method is used to remove a group from the OPC Server
- ///////////////////////////////////////////////////////////////////////////
- HRESULT CAppServer::OPCRemoveGroup (LPWSTR szGrpName)
- {
- HRESULT hr ;
- CGroup GrpNum ;
- if (!CheckGroupName(szGrpName, GrpNum))
- {
- hr = m_pIOPCServer->RemoveGroup(GroupNumber[GrpNum.m_nGroupNo].m_GroupHandle, FALSE) ;
- m_pIOPCGroupStateMgt[GrpNum.m_nGroupNo].Release() ;
- // Reset all the Group Variables to initial value
- GroupNumber[GrpNum.m_nGroupNo].m_szGrpName[0] = L'\0' ;
- GroupNumber[GrpNum.m_nGroupNo].m_GroupHandle = 0 ;
- GroupNumber[GrpNum.m_nGroupNo].m_NoOfItems = 0 ;
- GroupNumber[GrpNum.m_nGroupNo].m_nGroupNo = -1 ;
- m_nGroupNo = -1 ;
- m_nTotalGroups-- ;
- return hr ;
- }
- else
- return _OPC_INVALID_GROUP_NAME ;
- }
- ///////////////////////////////////////////////////////////////////////////
- // This Method is for disconnecting the OPC Server
- ///////////////////////////////////////////////////////////////////////////
- HRESULT CAppServer::OPCDisconnect ()
- {
- // Check all groups in case some are not released
- for (int nGrpNo=0;nGrpNo<m_nTotalGroups;nGrpNo++)
- {
- if (GroupNumber[nGrpNo].m_GroupHandle)
- m_pIOPCGroupStateMgt[nGrpNo].Release() ;
- }
- pcSink->Release(); // OLE should clean this up, but may not have time!
- m_pIOPCServer.Release() ;
- m_sTagNameAll.RemoveAll();
- m_sAddTagName.RemoveAll();
- delete []m_pcItem;
- m_pcItem = NULL;
- return S_OK ;
- }
- ///////////////////////////////////////////////////////////////////////////
- // This Method can be used for testing errors
- ///////////////////////////////////////////////////////////////////////////
- void CAppServer::OPCpErrors (HRESULT* pErrors, int NoOfItems)
- {
- for (int i=0; i<NoOfItems; i++)
- {
- switch (pErrors[i])
- {
- case OPC_E_INVALIDHANDLE:
- wprintf (L"pErrors[i] = OPC_E_INVALIDHANDLE\n") ;
- break ;
-
- case OPC_E_UNKNOWNITEMID:
- wprintf (L"pErrors[i] = OPC_E_UNKNOWNITEMID\n") ;
- break ;
- case OPC_E_RANGE:
- wprintf (L"pErrors[i] = OPC_E_RANGE\n") ;
- break ;
- case E_FAIL:
- wprintf (L"pErrors[i] = E_FAIL\n") ;
- break ;
- default:
- break ;
- }
- }
- }
- HRESULT CAppServer::getAllTagName( CStringArray *saTags )
- {
- m_sTagNameAll.RemoveAll();
- saTags->RemoveAll();
- VARTYPE m_vt = VT_EMPTY ;
- OPCNAMESPACETYPE nameSpaceType;
- HRESULT hr = 0;
- nameSpaceType = OPC_NS_HIERARCHIAL;
- IEnumString* pEnumString = NULL;
- const unsigned long NEXT_COUNT = 1000 ;
- //LPWSTR pName[NEXT_COUNT];
- CComQIPtr<IOPCBrowseServerAddressSpace, &IID_IOPCBrowseServerAddressSpace> m_pIOPCBrowseServerAddressSpace (m_pIOPCServer);
- if (!m_pIOPCServer || !m_pIOPCBrowseServerAddressSpace)
- return _OPC_INVALID_OBJECT;
- HTREEITEM first=0;
- if( m_pIOPCServer )
- {
- IEnumString* pEnumString = NULL;
- CString csAdd;
- HRESULT hr = m_pIOPCBrowseServerAddressSpace->BrowseOPCItemIDs(OPC_FLAT,
- csAdd.AllocSysString(),
- VT_EMPTY,
- 0,//OPC_READABLE | OPC_WRITEABLE,
- &pEnumString);
- if( hr == S_OK )
- {
- LPWSTR pName = NULL;
- ULONG count = 0;
- while( (hr = pEnumString->Next(1, &pName, &count)) == S_OK )
- {
- // CString does translation from UNICODE to native type
- // (depends on the way the application is built)
- CString name( pName );
- m_sTagNameAll.Add( name );
- saTags->Add( name );
- //pNameDst[cnt++] = pName;
- //InsertChildren( m_pIOPCBrowseServerAddressSpace,pName,pNameDst,cnt );
- CoTaskMemFree( pName );
- }
- pEnumString->Release();
- }
- }
- return S_OK;
- }
- HRESULT CAppServer::BrowseServerAddressSpace(CString *pNameDst, unsigned int& cnt)
- {
- #if 1
- VARTYPE m_vt = VT_EMPTY ;
- OPCNAMESPACETYPE nameSpaceType;
- HRESULT hr = 0;
- nameSpaceType = OPC_NS_HIERARCHIAL;
- IEnumString* pEnumString = NULL;
- const unsigned long NEXT_COUNT = 1000 ;
- //LPWSTR pName[NEXT_COUNT];
- CComQIPtr<IOPCBrowseServerAddressSpace, &IID_IOPCBrowseServerAddressSpace> m_pIOPCBrowseServerAddressSpace (m_pIOPCServer);
- if (!m_pIOPCServer || !m_pIOPCBrowseServerAddressSpace)
- return _OPC_INVALID_OBJECT;
- HTREEITEM first=0;
- if( m_pIOPCServer )
- {
- IEnumString* pEnumString = NULL;
- CString csAdd;
- HRESULT hr = m_pIOPCBrowseServerAddressSpace->BrowseOPCItemIDs(OPC_FLAT,
- csAdd.AllocSysString(),
- VT_EMPTY,
- 0,//OPC_READABLE | OPC_WRITEABLE,
- &pEnumString);
- if( hr == S_OK )
- {
- LPWSTR pName = NULL;
- ULONG count = 0;
- while( (hr = pEnumString->Next(1, &pName, &count)) == S_OK )
- {
- // CString does translation from UNICODE to native type
- // (depends on the way the application is built)
- CString name( pName );
- pNameDst[cnt++]= pName;
- //pNameDst[cnt++] = pName;
- //InsertChildren( m_pIOPCBrowseServerAddressSpace,pName,pNameDst,cnt );
- CoTaskMemFree( pName );
- }
- pEnumString->Release();
- }
- }
- #else
- VARTYPE m_vt = VT_EMPTY ;
- OPCNAMESPACETYPE nameSpaceType;
- HRESULT hr = 0;
- nameSpaceType = OPC_NS_HIERARCHIAL;
- IEnumString* pEnumString = NULL;
- const unsigned long NEXT_COUNT = 1000 ;
- LPWSTR pName[NEXT_COUNT];
- CComQIPtr<IOPCBrowseServerAddressSpace, &IID_IOPCBrowseServerAddressSpace> m_pIOPCBrowseServerAddressSpace (m_pIOPCServer);
- if (!m_pIOPCServer || !m_pIOPCBrowseServerAddressSpace)
- return _OPC_INVALID_OBJECT;
- m_pIOPCBrowseServerAddressSpace->QueryOrganization(&nameSpaceType);
- if( nameSpaceType == OPC_NS_HIERARCHIAL ) // show a tree
- {
- hr = m_pIOPCBrowseServerAddressSpace->BrowseOPCItemIDs(OPC_BRANCH,
- L"*RQE*",
- m_vt,
- 0,
- &pEnumString);
- if( SUCCEEDED(hr) )
- {
- unsigned long count = 0;
- do
- {
- hr = pEnumString->Next(NEXT_COUNT, &pName[0], &count);
- for( ULONG index=0; index<count; index++ )
- {
- //wcscpy (pzName[index], pName[index]) ;
- CoTaskMemFree( pName[index] );
- CString s;
- s = pName[index];
- //AfxMessageBox( s );
- }
- }
- while( hr == S_OK );
- pEnumString->Release();
- *cnt = count ;
- }
- }
- else
- {
- hr = m_pIOPCBrowseServerAddressSpace->BrowseOPCItemIDs(OPC_LEAF,
- L"*RQE*",
- m_vt,
- 0,
- &pEnumString);
- if( SUCCEEDED(hr) )
- {
- unsigned long count = 0;
- do
- {
- hr = pEnumString->Next(NEXT_COUNT, &pName[0], &count);
- for( ULONG index=0; index<count; index++ )
- {
- //wcscpy (pzName[index], pName[index]) ;
- CoTaskMemFree( pName[index] );
- }
- }
- while( hr == S_OK );
- pEnumString->Release();
- }
- }
- #endif
- return hr ;
- }
- HRESULT CAppServer::BrowseServerAddressSpace(CTreeCtrl *pTreeCtrl,CStringArray *saTags)
- {
- VARTYPE m_vt = VT_EMPTY ;
- OPCNAMESPACETYPE nameSpaceType;
- HRESULT hr = 0;
- nameSpaceType = OPC_NS_HIERARCHIAL;
- IEnumString* pEnumString = NULL;
- const unsigned long NEXT_COUNT = 1000 ;
- //LPWSTR pName[NEXT_COUNT];
- CComQIPtr<IOPCBrowseServerAddressSpace, &IID_IOPCBrowseServerAddressSpace> m_pIOPCBrowseServerAddressSpace (m_pIOPCServer);
- if (!m_pIOPCServer || !m_pIOPCBrowseServerAddressSpace)
- return _OPC_INVALID_OBJECT;
- if( pTreeCtrl )
- pTreeCtrl->SetRedraw(FALSE);
- //m_List.SetRedraw(FALSE);
- HTREEITEM first=0;
- //UpdateData();
- if( pTreeCtrl )
- pTreeCtrl->DeleteAllItems();
- if( m_pIOPCServer )
- {
- IEnumString* pEnumString = NULL;
- CString csAdd;
- HRESULT hr = m_pIOPCBrowseServerAddressSpace->BrowseOPCItemIDs(OPC_BRANCH,
- csAdd.AllocSysString(),
- VT_EMPTY,
- OPC_READABLE | OPC_WRITEABLE,
- &pEnumString);
- if( hr == S_OK )
- {
- LPWSTR pName = NULL;
- ULONG count = 0;
- while( (hr = pEnumString->Next(1, &pName, &count)) == S_OK )
- {
- // CString does translation from UNICODE to native type
- // (depends on the way the application is built)
- CString name( pName );
- HTREEITEM item=NULL;
- if( pTreeCtrl )
- item = pTreeCtrl->InsertItem( name );
- if( first == 0 )
- first = item;
- if( pTreeCtrl )
- InsertChildren( m_pIOPCBrowseServerAddressSpace,pName, item,pTreeCtrl );
- CoTaskMemFree( pName );
- }
- pEnumString->Release();
- }
- }
- if( pTreeCtrl )
- pTreeCtrl->SelectItem( first );
- if( pTreeCtrl )
- pTreeCtrl->SetRedraw(TRUE);
- //m_List.SetRedraw(TRUE);
- if( saTags )
- getAllTagName( saTags );
- return hr ;
- }
- void CAppServer::InsertChildren( CComQIPtr<IOPCBrowseServerAddressSpace, &IID_IOPCBrowseServerAddressSpace> pcBrowse,LPWSTR child, HTREEITEM hParent,CTreeCtrl *pTreeCtrl )
- {
- HRESULT hr = pcBrowse->ChangeBrowsePosition( OPC_BROWSE_DOWN, (LPCWSTR)child );
- if( FAILED(hr) )
- return;
- IEnumString* pEnumString = NULL;
- CString csAdd;
- hr = pcBrowse->BrowseOPCItemIDs( OPC_BRANCH,
- csAdd.AllocSysString(),
- VT_EMPTY,
- OPC_READABLE|OPC_WRITEABLE,
- &pEnumString);
-
- if( hr == S_OK )
- {
- LPWSTR pName = NULL;
- ULONG count = 0;
- while( (hr = pEnumString->Next(1, &pName, &count)) == S_OK )
- {
- CString name( pName ); // translation
- HTREEITEM item = pTreeCtrl->InsertItem( name, hParent );
- InsertChildren( pcBrowse,pName, item,pTreeCtrl );
- CoTaskMemFree( pName );
- }
- pEnumString->Release();
- }
- hr = pcBrowse->ChangeBrowsePosition( OPC_BROWSE_UP, L"" );
- }
- void CAppServer::InsertChildren( CComQIPtr<IOPCBrowseServerAddressSpace, &IID_IOPCBrowseServerAddressSpace> pcBrowse,LPWSTR child,LPWSTR *pNameDst, unsigned int& cnt )
- {
- HRESULT hr = pcBrowse->ChangeBrowsePosition( OPC_BROWSE_DOWN, (LPCWSTR)child );
- if( FAILED(hr) )
- return;
- IEnumString* pEnumString = NULL;
- CString csAdd;
- hr = pcBrowse->BrowseOPCItemIDs( OPC_FLAT,
- csAdd.AllocSysString(),
- VT_EMPTY,
- OPC_READABLE|OPC_WRITEABLE,
- &pEnumString);
-
- if( hr == S_OK )
- {
- LPWSTR pName = NULL;
- ULONG count = 0;
- while( (hr = pEnumString->Next(1, &pName, &count)) == S_OK )
- {
- CString name( pName ); // translation
- // pNameDst[cnt++] = pName;
- InsertChildren( pcBrowse,pName,pNameDst,cnt );
- CoTaskMemFree( pName );
- }
- pEnumString->Release();
- }
- hr = pcBrowse->ChangeBrowsePosition( OPC_BROWSE_UP, L"" );
- }
- bool CAppServer::IsOK () const { return (m_pIOPCServer != NULL); }
|