数据订阅主要用到了一个接口——IOPCDataCallback,该接口是在opcda.h中定义的,因为它是个抽像类,所以需要实现OnDataChange、OnReadComplete、OnWriteComplete、OnCancelComplete以及QueryInterface、AddRef、Release七个方法,为了避免重写后面三种方法,笔者才用了COM组件的模板类,就只需要解决上面四种方法即可(其实笔者也不太清楚为什么要这样做,但是仿佛使用了模板类以后,程序能够编译通过,要是采用IConnectionPointContainer这种方式,需要把七种方法全部都实现,所以果断就这样写了)。
数据订阅主要用到了一个接口——IOPCDataCallback,该接口是在opcda.h中定义的,因为它是个抽像类,所以需要实现OnDataChange、OnReadComplete、OnWriteComplete、OnCancelComplete以及QueryInterface、AddRef、Release七个方法,为了避免重写后面三种方法,笔者才用了COM组件的模板类,就只需要解决上面四种方法即可(其实笔者也不太清楚为什么要这样做,但是仿佛使用了模板类以后,程序能够编译通过,要是采用IConnectionPointContainer这种方式,需要把七种方法全部都实现,所以果断就这样写了)。
笔者重写了一个类,继承自IOPCDataCallback,命名为COPCDataCallback,其头文件为:
#include
#include
#include "opcda.h"
//
// Callback.h : Declaration of callback class and definition of minor methods
//
//---------------------------------------------------------
// (c) COPYRIGHT 2003,2004 http://www.opc-china.com INC.
// ALL RIGHTS RESERVED
// Original Author:geekCarnegie
// Original Author Email:[email protected]
//---------------------------------------------------------
class COPCDataCallback : public IOPCDataCallback,
public CComObjectRootEx
{
public:
COPCDataCallback() {};
virtual ~COPCDataCallback() { ; };
BEGIN_COM_MAP(COPCDataCallback)
COM_INTERFACE_ENTRY(IOPCDataCallback)
END_COM_MAP()
// IOPCDataCallback
STDMETHODIMP OnDataChange(
/* [in] */ DWORD dwTransid,
/* [in] */ OPCHANDLE hGroup,
/* [in] */ HRESULT hrMasterquality,
/* [in] */ HRESULT hrMastererror,
/* [in] */ DWORD dwCount,
/* [size_is][in] */ OPCHANDLE __RPC_FAR *phClientItems,
/* [size_is][in] */ VARIANT __RPC_FAR *pvValues,
/* [size_is][in] */ WORD __RPC_FAR *pwQualities,
/* [size_is][in] */ FILETIME __RPC_FAR *pftTimeStamps,
/* [size_is][in] */ HRESULT __RPC_FAR *pErrors);
STDMETHODIMP OnReadComplete(
/* [in] */ DWORD dwTransid,
/* [in] */ OPCHANDLE hGroup,
/* [in] */ HRESULT hrMasterquality,
/* [in] */ HRESULT hrMastererror,
/* [in] */ DWORD dwCount,
/* [size_is][in] */ OPCHANDLE __RPC_FAR *phClientItems,
/* [size_is][in] */ VARIANT __RPC_FAR *pvValues,
/* [size_is][in] */ WORD __RPC_FAR *pwQualities,
/* [size_is][in] */ FILETIME __RPC_FAR *pftTimeStamps,
/* [size_is][in] */ HRESULT __RPC_FAR *pErrors);
STDMETHODIMP OnWriteComplete(
/* [in] */ DWORD dwTransid,
/* [in] */ OPCHANDLE hGroup,
/* [in] */ HRESULT hrMastererr,
/* [in] */ DWORD dwCount,
/* [size_is][in] */ OPCHANDLE __RPC_FAR *pClienthandles,
/* [size_is][in] */ HRESULT __RPC_FAR *pErrors);
STDMETHODIMP OnCancelComplete(
/* [in] */ DWORD dwTransid,
/* [in] */ OPCHANDLE hGroup)
{
return S_OK;
};
};
STDMETHODIMP COPCDataCallback::OnDataChange( // OnDataChange notifications
DWORD dwTransID, // 0 for normal OnDataChange events, non-zero for Refreshes
OPCHANDLE hGroup, // client group handle
HRESULT hrMasterQuality, // S_OK if all qualities are GOOD, otherwise S_FALSE
HRESULT hrMasterError, // S_OK if all errors are S_OK, otherwise S_FALSE
DWORD dwCount, // number of items in the lists that follow
OPCHANDLE *phClientItems, // item client handles
VARIANT *pvValues, // item data
WORD *pwQualities, // item qualities
FILETIME *pftTimeStamps, // item timestamps
HRESULT *pErrors) // item errors
{
std::cout << std::endl;
std::cout << "数据第" << changeFlag << "次变更:" << std::endl;
DWORD i;
for (i = 0; i
其中OnDataChange方法的实现代码为:
STDMETHODIMP COPCDataCallback::OnDataChange( // OnDataChange notifications
DWORD dwTransID, // 0 for normal OnDataChange events, non-zero for Refreshes
OPCHANDLE hGroup, // client group handle
HRESULT hrMasterQuality, // S_OK if all qualities are GOOD, otherwise S_FALSE
HRESULT hrMasterError, // S_OK if all errors are S_OK, otherwise S_FALSE
DWORD dwCount, // number of items in the lists that follow
OPCHANDLE *phClientItems, // item client handles
VARIANT *pvValues, // item data
WORD *pwQualities, // item qualities
FILETIME *pftTimeStamps, // item timestamps
HRESULT *pErrors) // item errors
{
std::cout << std::endl;
std::cout << "数据第" << changeFlag << "次变更:" << std::endl;
DWORD i;
for (i = 0; i
OnReadComplete的代码为:
STDMETHODIMP COPCDataCallback::OnReadComplete( // OnReadComplete notifications
DWORD dwTransID, // Transaction ID returned by the server when the read was initiated
OPCHANDLE hGroup, // client group handle
HRESULT hrMasterQuality, // S_OK if all qualities are GOOD, otherwise S_FALSE
HRESULT hrMasterError, // S_OK if all errors are S_OK, otherwise S_FALSE
DWORD dwCount, // number of items in the lists that follow
OPCHANDLE *phClientItems, // item client handles
VARIANT *pvValues, // item data
WORD *pwQualities, // item qualities
FILETIME *pftTimeStamps, // item timestamps
HRESULT *pErrors) // item errors
{
std::cout << std::endl;
std::cout << "数据获取中..." << std::endl;
if (pErrors[0] == S_OK)
{
DWORD i;
for (i = 0; i
在主程序中先获取组状态:
/*组更新状态*/
hr = pIOPCItemMgt->QueryInterface(IID_IOPCGroupStateMgt, /*OUT*/(void**)&pIOPCGroupStateMgt); //得到第十个指针
ASSERT(pIOPCGroupStateMgt);
if (FAILED(hr))
{
cout << "获取IOPCGroupStateMgt接口失败..." << endl;
if (pItemResult) CoTaskMemFree(pItemResult);
if (pErrors) CoTaskMemFree(pErrors);
CoTaskMemFree(&hOPCServer1);
CoTaskMemFree(&hOPCServer2); //第六个内存释放
CoTaskMemFree(&itemArray); //第五个内存释放
CoTaskMemFree(&clsid); //第四个内存释放
CoTaskMemFree(&catID); //第三个内存释放
CoTaskMemFree(&mqi); //第二个内存释放
CoTaskMemFree(&si); //第一个内存释放
if (pIOPCGroupStateMgt) pIOPCGroupStateMgt->Release(); //第十个指针释放
pIOPCGroupStateMgt = NULL;
if (pIOPCItemMgt) pIOPCItemMgt->Release(); //第五个指针释放
pIOPCItemMgt = NULL;
if (pIServer) pIServer->Release(); //第四个指针释放
pIServer = NULL;
if (pIUnknown) pIUnknown->Release(); //第三个指针释放
pIUnknown = NULL;
if (pIEnumGUID) pIEnumGUID->Release(); //第二个指针释放
pIEnumGUID = NULL;
if (pIServerList) pIServerList->Release(); //第一个指针释放
pIServerList = NULL;
return 1;
}
else if (SUCCEEDED(hr)) {
cout << "已获取到IOPCGroupStateMgt接口..." << endl;
}
DWORD dwRevUpdateRate = 10;
BOOL bActivateGroup = TRUE;
hr = pIOPCGroupStateMgt->SetState(/*[in] RequestedUpdateRate*/ NULL, /*[out] RevisedUpdateRate */ &dwRevUpdateRate, /*[in] ActiveFlag for Group */ &bActivateGroup, /*[in] TimeBias*/ NULL, /*[in] PercentDeadband*/ NULL, /*[in] LCID*/ NULL, NULL);
然后在主程序中调用COPCDataCallback类,设置回调:
CComObject *pCOPCDataCallback;
CComObject::CreateInstance(&pCOPCDataCallback);
LPUNKNOWN pCbUnk;
pCbUnk = pCOPCDataCallback->GetUnknown();
DWORD dwCookie;
HRESULT hRes = AtlAdvise(pIOPCGroupStateMgt, pCbUnk, IID_IOPCDataCallback, &dwCookie);
if (FAILED(hRes)) {
cout << "数据订阅回调设置失败..." << endl;
if (pItemResult) CoTaskMemFree(pItemResult);
if (pErrors) CoTaskMemFree(pErrors);
CoTaskMemFree(&hOPCServer1);
CoTaskMemFree(&hOPCServer2); //第六个内存释放
CoTaskMemFree(&itemArray); //第五个内存释放
CoTaskMemFree(&clsid); //第四个内存释放
CoTaskMemFree(&catID); //第三个内存释放
CoTaskMemFree(&mqi); //第二个内存释放
CoTaskMemFree(&si); //第一个内存释放
if (pIOPCGroupStateMgt) pIOPCGroupStateMgt->Release(); //第十个指针释放
pIOPCGroupStateMgt = NULL;
if (pIOPCItemMgt) pIOPCItemMgt->Release(); //第五个指针释放
pIOPCItemMgt = NULL;
if (pIServer) pIServer->Release(); //第四个指针释放
pIServer = NULL;
if (pIUnknown) pIUnknown->Release(); //第三个指针释放
pIUnknown = NULL;
if (pIEnumGUID) pIEnumGUID->Release(); //第二个指针释放
pIEnumGUID = NULL;
if (pIServerList) pIServerList->Release(); //第一个指针释放
pIServerList = NULL;
return 1;
}
else if (SUCCEEDED(hRes)) {
cout << "数据订阅回调设置成功..." << endl;
}
system("pause>nul");
最后释放指针,程序退出,数据订阅完毕。