写个干净优雅的OPC程序及OPC SDK质量分析

上篇提到了回调函数及SDK质量的问题,今天继续谈谈如何写个自己感觉满意的OPC程序。何为干净优雅?个人的理解就是在客户端要及时地释放不再需要的资源,在客户端创建的回调函数(如IOPCDataCallback,IOPCShutdown等)事例要优雅地退出,在服务端可以看见被客户端创建的进程在客户端释放资源后自行退出,说明客户端不再有服务端资源的占用或调用。

下面是我在客户端针对DA干净退出的样本,

void cleanServer(IOPCServer* server, IOPCItemMgt* pOPCItemMgt, ShutdownCallback* pShutdownCallback, DataCallback* pDataCallback) {

	/* clean up connection points held by server */

	CComPtr<IConnectionPointContainer> ipCPContainer;

	HRESULT hResult = server->QueryInterface(IID_IConnectionPointContainer, (void**)& ipCPContainer);

	if (FAILED(hResult))
	{
		handleError(hResult, "IID_IConnectionPointContainer in cleanServer()");
		return;
	}

	CComPtr<IEnumConnectionPoints> pEnumCP;
	hResult = ipCPContainer->EnumConnectionPoints(&pEnumCP);

	if (SUCCEEDED(hResult)) {
		CComPtr< IConnectionPoint> CP;
		ULONG fetched;

		while ((pEnumCP->Next(1, &CP.p, &fetched)) == S_OK) {
			CComPtr<IEnumConnections> pEnumCon;
			hResult = CP->EnumConnections(&pEnumCon.p);

			if (SUCCEEDED(hResult)) {
				CONNECTDATA rgcd = { NULL };
				ULONG pcFetched;

				while (pEnumCon->Next(1, &rgcd, &pcFetched) == S_OK) {
					hResult = CP->Unadvise(rgcd.dwCookie);
					rgcd.pUnk->Release();
				}
			}

			CP.p->Release();
		}
	}

	/* clean up connection points etc held by groups */
	if (pOPCItemMgt) {
		CComPtr< IEnumOPCItemAttributes> pEnumOPCItemAttributes;
		hResult = pOPCItemMgt->CreateEnumerator(IID_IEnumOPCItemAttributes, (LPUNKNOWN*)& pEnumOPCItemAttributes.p);

		if (SUCCEEDED(hResult)) {
			OPCITEMATTRIBUTES* pOPCITEMATTRIBUTES = NULL;
			ULONG pcFetched;

			while (pEnumOPCItemAttributes->Next(1, &pOPCITEMATTRIBUTES, &pcFetched) == S_OK) {
				OPCHANDLE hServerHandle = pOPCITEMATTRIBUTES->hServer;

				HRESULT* ppErrors = NULL;
				hResult = pOPCItemMgt->RemoveItems(1, &hServerHandle, &ppErrors);

				CoTaskMemFree(pOPCITEMATTRIBUTES);
			}
		}

		CComPtr<IConnectionPointContainer> ipGroupCPContainer;

		hResult = pOPCItemMgt->QueryInterface(IID_IConnectionPointContainer, (void**)& ipGroupCPContainer);

		if (SUCCEEDED(hResult)) {
			CComPtr<IEnumConnectionPoints> pEnumCP;
			hResult = ipGroupCPContainer->EnumConnectionPoints(&pEnumCP);

			if (SUCCEEDED(hResult)) {
				CComPtr< IConnectionPoint> CP;
				ULONG uFetched;

				while ((pEnumCP->Next(1, &CP.p, &uFetched)) == S_OK) {
					CComPtr<IEnumConnections> pEnumCon;
					hResult = CP->EnumConnections(&pEnumCon.p);

					if (SUCCEEDED(hResult)) {
						CONNECTDATA rgcd = { NULL };
						ULONG pcFetched;

						while (pEnumCon->Next(1, &rgcd, &pcFetched) == S_OK) {
							CP->Unadvise(rgcd.dwCookie);
							rgcd.pUnk->Release();
						}
					}

					CP.p->Release();
				}
			}
		}
	}

	if (pShutdownCallback) {
		pShutdownCallback->Release();
		pShutdownCallback = NULL;
	}

	if (pDataCallback) {
		pDataCallback->Release();
		pDataCallback = NULL;
	}

	/* release count created by addGroup */
	if (pOPCItemMgt)
		pOPCItemMgt->Release();

	/* releasing reference count created by CoCretaeInstance. Reference couunt should be zero after funcion out of scope */
	server->Release();
}

程序主要分二部分,第一是针对IOPCServer的资源释放,第二部分是针对IOPCItemMgt的资源释放,这些释放都是发生在服务端的,最后是关于客户端本身的回调函数的资源释放,我在上面加了注释应该一目了然了。在IOPCServer中涉及的服务端资源有IConnectionPointContainer及下面的IConnectionPoint,还有它下面的IEnumConnections,它们是针对IOPCShutdown引起的资源释放。在IOPCItemMgt涉及的服务端资源有IEnumOPCItemAttributes,主要是释放客户端AddItems函数调用所占用的服务端资源。还有针对IConnectionPointContainer/IConnectionPoint/IEnumConnections的资源释放,主要是为回调函数IOPCDataCallback来释放在服务端占用的资源。我也是在这里发现了SDK的另一个没有执行的接口,怎么发现的呢?我先是用Matrikon的DA模拟服务器来测试,断点处返回的hResult是S_OK,

换到SDK提供的DA 3.0服务器样本程序,得到的结果是不一样的,见下,

hResult明白无误地告诉我该接口IEnumConnections不被SDK支持,我不得不看看服务端到底是怎么处理的,在COpcConnectionPoint.cpp中如下,

在这里QueryInterface给出了相同的答案,不支持该接口,哪么COpcConnectionPoint类到底支持什么接口?

显而易见它不支持IEnumConnections,只支持IConnectionPoint,那我在这里加上IEnumConnections有没有用?答案是否定的,因为OPC SDK中根本没有支持IEnumConnections的类存在,如下图所示,有COpcEnumCPs.cpp,COpcEnumString.cpp和COpcEnumUnknown.cpp,不能不说OPC SDK发在这么多年质量还是有缺陷呀,虽然有这么多人在使用。俺们是不是考虑加上个COpcEnumConnection.cpp做做贡献?如果有人对我的干净优雅的客户端感兴趣在这留个言我可以发给你们玩玩:-)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值