OPC数据订阅-------OPC(第八篇)

    数据订阅主要用到了一个接口——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,其头文件为:

  1. #include <atlbase.h>  
  2. #include <atlcom.h>  
  3. #include "opcda.h"  
  4. //  
  5. // Callback.h : Declaration of callback class and definition of minor methods  
  6. //  
  7. //---------------------------------------------------------  
  8. // (c) COPYRIGHT 2003,2004 http://www.opc-china.com INC.  
  9. // ALL RIGHTS RESERVED  
  10. // Original Author:geekCarnegie   
  11. // Original Author Email:geekcarnegie@gmail.com  
  12. //---------------------------------------------------------  
  13. class COPCDataCallback : public IOPCDataCallback,  
  14.        public CComObjectRootEx<CComSingleThreadModel>  
  15. {  
  16.   
  17. public:  
  18.     COPCDataCallback() {};  
  19.     virtual ~COPCDataCallback() { ; };  
  20.   
  21.     BEGIN_COM_MAP(COPCDataCallback)  
  22.         COM_INTERFACE_ENTRY(IOPCDataCallback)  
  23.     END_COM_MAP()  
  24.   
  25.     // IOPCDataCallback  
  26.     STDMETHODIMP  OnDataChange(  
  27.         /* [in] */ DWORD dwTransid,  
  28.         /* [in] */ OPCHANDLE hGroup,  
  29.         /* [in] */ HRESULT hrMasterquality,  
  30.         /* [in] */ HRESULT hrMastererror,  
  31.         /* [in] */ DWORD dwCount,  
  32.         /* [size_is][in] */ OPCHANDLE __RPC_FAR *phClientItems,  
  33.         /* [size_is][in] */ VARIANT __RPC_FAR *pvValues,  
  34.         /* [size_is][in] */ WORD __RPC_FAR *pwQualities,  
  35.         /* [size_is][in] */ FILETIME __RPC_FAR *pftTimeStamps,  
  36.         /* [size_is][in] */ HRESULT __RPC_FAR *pErrors);  
  37.     STDMETHODIMP  OnReadComplete(  
  38.         /* [in] */ DWORD dwTransid,  
  39.         /* [in] */ OPCHANDLE hGroup,  
  40.         /* [in] */ HRESULT hrMasterquality,  
  41.         /* [in] */ HRESULT hrMastererror,  
  42.         /* [in] */ DWORD dwCount,  
  43.         /* [size_is][in] */ OPCHANDLE __RPC_FAR *phClientItems,  
  44.         /* [size_is][in] */ VARIANT __RPC_FAR *pvValues,  
  45.         /* [size_is][in] */ WORD __RPC_FAR *pwQualities,  
  46.         /* [size_is][in] */ FILETIME __RPC_FAR *pftTimeStamps,  
  47.         /* [size_is][in] */ HRESULT __RPC_FAR *pErrors);  
  48.     STDMETHODIMP  OnWriteComplete(  
  49.         /* [in] */ DWORD dwTransid,  
  50.         /* [in] */ OPCHANDLE hGroup,  
  51.         /* [in] */ HRESULT hrMastererr,  
  52.         /* [in] */ DWORD dwCount,  
  53.         /* [size_is][in] */ OPCHANDLE __RPC_FAR *pClienthandles,  
  54.         /* [size_is][in] */ HRESULT __RPC_FAR *pErrors);  
  55.     STDMETHODIMP  OnCancelComplete(  
  56.         /* [in] */ DWORD dwTransid,  
  57.         /* [in] */ OPCHANDLE hGroup)  
  58.     {  
  59.         return S_OK;  
  60.     };  
  61. };  
  62.       
  63. STDMETHODIMP COPCDataCallback::OnDataChange(  // OnDataChange notifications  
  64.     DWORD dwTransID,   // 0 for normal OnDataChange events, non-zero for Refreshes  
  65.     OPCHANDLE hGroup,   // client group handle  
  66.     HRESULT hrMasterQuality, // S_OK if all qualities are GOOD, otherwise S_FALSE  
  67.     HRESULT hrMasterError,  // S_OK if all errors are S_OK, otherwise S_FALSE  
  68.     DWORD dwCount,    // number of items in the lists that follow  
  69.     OPCHANDLE *phClientItems, // item client handles  
  70.     VARIANT *pvValues,   // item data  
  71.     WORD *pwQualities,   // item qualities  
  72.     FILETIME *pftTimeStamps, // item timestamps  
  73.     HRESULT *pErrors)   // item errors   
  74. {  
  75.     std::cout << std::endl;  
  76.     std::cout << "数据第" << changeFlag << "次变更:" << std::endl;  
  77.     DWORD i;  
  78.     for (i = 0; i<dwCount; i++)  
  79.     {  
  80.         value[i] = pvValues[i].fltVal;  
  81.         quility[i] = GetQualityText(pwQualities[i]);  
  82.         timestamp[i] = COleDateTime(pftTimeStamps[i]).Format();  
  83.     }  
  84.     std::cout << "数据变更完毕..." << std::endl;  
  85.     changeFlag++;  
  86.     return S_OK;  
  87. };</span>  
#include <atlbase.h>
#include <atlcom.h>
#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:geekcarnegie@gmail.com
//---------------------------------------------------------
class COPCDataCallback : public IOPCDataCallback,
	   public CComObjectRootEx<CComSingleThreadModel>
{

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<dwCount; i++)
	{
		value[i] = pvValues[i].fltVal;
		quility[i] = GetQualityText(pwQualities[i]);
		timestamp[i] = COleDateTime(pftTimeStamps[i]).Format();
	}
	std::cout << "数据变更完毕..." << std::endl;
	changeFlag++;
	return S_OK;
};</span>

    其中OnDataChange方法的实现代码为:

  1. STDMETHODIMP COPCDataCallback::OnDataChange(  // OnDataChange notifications  
  2.     DWORD dwTransID,   // 0 for normal OnDataChange events, non-zero for Refreshes  
  3.     OPCHANDLE hGroup,   // client group handle  
  4.     HRESULT hrMasterQuality, // S_OK if all qualities are GOOD, otherwise S_FALSE  
  5.     HRESULT hrMasterError,  // S_OK if all errors are S_OK, otherwise S_FALSE  
  6.     DWORD dwCount,    // number of items in the lists that follow  
  7.     OPCHANDLE *phClientItems, // item client handles  
  8.     VARIANT *pvValues,   // item data  
  9.     WORD *pwQualities,   // item qualities  
  10.     FILETIME *pftTimeStamps, // item timestamps  
  11.     HRESULT *pErrors)   // item errors   
  12. {  
  13.     std::cout << std::endl;  
  14.     std::cout << "数据第" << changeFlag << "次变更:" << std::endl;  
  15.     DWORD i;  
  16.     for (i = 0; i<dwCount; i++)  
  17.     {  
  18.         value[i] = pvValues[i].fltVal;  
  19.         quility[i] = GetQualityText(pwQualities[i]);  
  20.         timestamp[i] = COleDateTime(pftTimeStamps[i]).Format();  
  21.     }  
  22.   
  23.     std::cout << "数据变更完毕..." << std::endl;  
  24.     changeFlag++;  
  25.     return S_OK;  
  26. };  
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<dwCount; i++)
	{
		value[i] = pvValues[i].fltVal;
		quility[i] = GetQualityText(pwQualities[i]);
		timestamp[i] = COleDateTime(pftTimeStamps[i]).Format();
	}

	std::cout << "数据变更完毕..." << std::endl;
	changeFlag++;
	return S_OK;
};

    OnReadComplete的代码为:

  1. STDMETHODIMP COPCDataCallback::OnReadComplete( // OnReadComplete notifications  
  2.     DWORD dwTransID,   // Transaction ID returned by the server when the read was initiated  
  3.     OPCHANDLE hGroup,   // client group handle  
  4.     HRESULT hrMasterQuality, // S_OK if all qualities are GOOD, otherwise S_FALSE  
  5.     HRESULT hrMasterError,  // S_OK if all errors are S_OK, otherwise S_FALSE  
  6.     DWORD dwCount,    // number of items in the lists that follow  
  7.     OPCHANDLE *phClientItems, // item client handles  
  8.     VARIANT *pvValues,   // item data  
  9.     WORD *pwQualities,   // item qualities  
  10.     FILETIME *pftTimeStamps, // item timestamps  
  11.     HRESULT *pErrors)   // item errors   
  12. {     
  13.     std::cout << std::endl;  
  14.     std::cout << "数据获取中..." << std::endl;  
  15.     if (pErrors[0] == S_OK)  
  16.     {  
  17.         DWORD i;  
  18.         for (i = 0; i<dwCount; i++)  
  19.         {  
  20.             readValue[i] = pvValues[i].fltVal;  
  21.             readQulity[i] = GetQualityText(pwQualities[i]);  
  22.             readTS[i] = COleDateTime(pftTimeStamps[i]).Format();  
  23.         }  
  24.     }  
  25.     else  
  26.     {  
  27.         CString readQuality = GetQualityText(pErrors[0]);  
  28.     }  
  29.     std::cout << "数据已全部读完..." << std::endl;  
  30.     return S_OK;  
  31. };  
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<dwCount; i++)
		{
			readValue[i] = pvValues[i].fltVal;
			readQulity[i] = GetQualityText(pwQualities[i]);
			readTS[i] = COleDateTime(pftTimeStamps[i]).Format();
		}
	}
	else
	{
		CString readQuality = GetQualityText(pErrors[0]);
	}
	std::cout << "数据已全部读完..." << std::endl;
	return S_OK;
};

    在主程序中先获取组状态:    

  1. /*组更新状态*/  
  2. hr = pIOPCItemMgt->QueryInterface(IID_IOPCGroupStateMgt, /*OUT*/(void**)&pIOPCGroupStateMgt); //得到第十个指针  
  3. ASSERT(pIOPCGroupStateMgt);  
  4.   
  5. if (FAILED(hr))  
  6. {  
  7.     cout << "获取IOPCGroupStateMgt接口失败..." << endl;  
  8.     if (pItemResult) CoTaskMemFree(pItemResult);  
  9.     if (pErrors) CoTaskMemFree(pErrors);  
  10.     CoTaskMemFree(&hOPCServer1);  
  11.     CoTaskMemFree(&hOPCServer2); //第六个内存释放  
  12.     CoTaskMemFree(&itemArray); //第五个内存释放  
  13.     CoTaskMemFree(&clsid); //第四个内存释放  
  14.     CoTaskMemFree(&catID); //第三个内存释放  
  15.     CoTaskMemFree(&mqi); //第二个内存释放  
  16.     CoTaskMemFree(&si); //第一个内存释放  
  17.     if (pIOPCGroupStateMgt) pIOPCGroupStateMgt->Release(); //第十个指针释放  
  18.     pIOPCGroupStateMgt = NULL;  
  19.     if (pIOPCItemMgt) pIOPCItemMgt->Release(); //第五个指针释放  
  20.     pIOPCItemMgt = NULL;  
  21.     if (pIServer) pIServer->Release(); //第四个指针释放  
  22.     pIServer = NULL;  
  23.     if (pIUnknown) pIUnknown->Release(); //第三个指针释放  
  24.     pIUnknown = NULL;  
  25.     if (pIEnumGUID) pIEnumGUID->Release(); //第二个指针释放  
  26.     pIEnumGUID = NULL;  
  27.     if (pIServerList) pIServerList->Release(); //第一个指针释放  
  28.     pIServerList = NULL;  
  29.     return 1;  
  30. }  
  31. else if (SUCCEEDED(hr)) {  
  32.     cout << "已获取到IOPCGroupStateMgt接口..." << endl;  
  33. }  
  34.   
  35. DWORD  dwRevUpdateRate = 10;  
  36. BOOL bActivateGroup = TRUE;  
  37.   
  38. hr = pIOPCGroupStateMgt->SetState(/*[in] RequestedUpdateRate*/ NULL, /*[out] RevisedUpdateRate */ &dwRevUpdateRate, /*[in] ActiveFlag for Group */ &bActivateGroup, /*[in] TimeBias*/ NULL, /*[in] PercentDeadband*/ NULL, /*[in] LCID*/ NULL, NULL);    </span>  
/*组更新状态*/
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);	</span>

    然后在主程序中调用COPCDataCallback类,设置回调:

  1. CComObject<COPCDataCallback> *pCOPCDataCallback;  
  2. CComObject<COPCDataCallback>::CreateInstance(&pCOPCDataCallback);  
  3.   
  4. LPUNKNOWN pCbUnk;  
  5. pCbUnk = pCOPCDataCallback->GetUnknown();  
  6. DWORD dwCookie;  
  7.   
  8. HRESULT hRes = AtlAdvise(pIOPCGroupStateMgt, pCbUnk, IID_IOPCDataCallback, &dwCookie);  
  9.   
  10. if (FAILED(hRes)) {  
  11.     cout << "数据订阅回调设置失败..." << endl;  
  12.     if (pItemResult) CoTaskMemFree(pItemResult);  
  13.     if (pErrors) CoTaskMemFree(pErrors);  
  14.     CoTaskMemFree(&hOPCServer1);  
  15.     CoTaskMemFree(&hOPCServer2); //第六个内存释放  
  16.     CoTaskMemFree(&itemArray); //第五个内存释放  
  17.     CoTaskMemFree(&clsid); //第四个内存释放  
  18.     CoTaskMemFree(&catID); //第三个内存释放  
  19.     CoTaskMemFree(&mqi); //第二个内存释放  
  20.     CoTaskMemFree(&si); //第一个内存释放  
  21.     if (pIOPCGroupStateMgt) pIOPCGroupStateMgt->Release(); //第十个指针释放  
  22.     pIOPCGroupStateMgt = NULL;  
  23.     if (pIOPCItemMgt) pIOPCItemMgt->Release(); //第五个指针释放  
  24.     pIOPCItemMgt = NULL;  
  25.     if (pIServer) pIServer->Release(); //第四个指针释放  
  26.     pIServer = NULL;  
  27.     if (pIUnknown) pIUnknown->Release(); //第三个指针释放  
  28.     pIUnknown = NULL;  
  29.     if (pIEnumGUID) pIEnumGUID->Release(); //第二个指针释放  
  30.     pIEnumGUID = NULL;  
  31.     if (pIServerList) pIServerList->Release(); //第一个指针释放  
  32.     pIServerList = NULL;  
  33.     return 1;  
  34. }  
  35. else if (SUCCEEDED(hRes)) {  
  36.     cout << "数据订阅回调设置成功..." << endl;  
  37. }  
CComObject<COPCDataCallback> *pCOPCDataCallback;
CComObject<COPCDataCallback>::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;
}

    在主程序的最后,笔者加了系统暂停,以便控制台程序能够在数据变更的时候就能够获取到变更的数据:

  1. system("pause>nul");  
system("pause>nul");
    最后释放指针,程序退出,数据订阅完毕。


  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值