OPC客户端分析 —— 读和写

上篇给大家分析了如何在客户端进行服务器查询,今天再分析下在客户端的读和写的操作。下面这个函数囊括各路类型的读写操作,如异步或同步等等,实用性很强。

HRESULT synReadOrWrite(serverGroup* serverGroup, bool read, bool async) {

	char *buffer = (char *)malloc(MAXBYTE);

	OPCITEMRESULT *pResults = NULL;
	OPCHANDLE *hServerItem = NULL;

	HRESULT hResult = S_OK;

	IOPCSyncIO *pIOPCSyncIO = NULL;
	IOPCAsyncIO2 *pIOPCAsyncIO2 = NULL;

	if (async) {

		if (serverGroup->groupInfo->ipCPC == NULL) {

			hResult = buildCallback(serverGroup);

			if (FAILED(hResult)) {

				_tprintf(_T("Failed in buildCallback.\n"));
				return hResult;
			}
		}

		hResult = serverGroup->groupInfo->ipMgt->QueryInterface(IID_IOPCAsyncIO2, (void**)&pIOPCAsyncIO2);
		showConsole = false;
	}
	else
		hResult = serverGroup->groupInfo->ipMgt->QueryInterface(IID_IOPCSyncIO, (void**)&pIOPCSyncIO);

	HRESULT *pErrors = NULL;

	if (FAILED(hResult))
	{
		_tprintf(_T("getting interface IID_IOPCSyncIO or IID_IOPCAsyncIO2 failed.\r\n"));
		goto end;
	}

	if (read) {
		_tprintf(_T("Enter tag names seperated by comma and press enter: "));

		fgets(buffer, MAXBYTE, stdin);

		size_t ln = strlen(buffer) - 1;
		if (buffer[ln] == '\n')
			buffer[ln] = '\0';

		char **result = NULL;
		size_t dwCount = 0;
		OPCITEMSTATE *pValues = NULL;

		if (strlen(buffer) == 0) {

			_tprintf(_T("tag names should be in format like this - tagName1, tagName2, tagName3\n"));
			hResult = E_INVALIDARG;

			goto end;
		}

		tokenizeString(buffer, ',', (char***)&result, &dwCount);

		pResults = (OPCITEMRESULT*)CoTaskMemAlloc(dwCount * sizeof(OPCITEMRESULT));
		hServerItem = (OPCHANDLE *)CoTaskMemAlloc(dwCount * sizeof(OPCHANDLE));
		pErrors = (HRESULT *)CoTaskMemAlloc(dwCount * sizeof(HRESULT));

		hResult = addItems(serverGroup->groupInfo->ipMgt, result, &pResults, &pErrors, dwCount);

		for (DWORD ii = 0; ii < dwCount; ii++) {
			if (!pErrors[ii])
				hServerItem[ii] = pResults[ii].hServer;
		}

		if (async) {
			DWORD dwCancelID;
			hResult = pIOPCAsyncIO2->Read(dwCount, hServerItem, *hServerItem, &dwCancelID, &pErrors); /* *hServerItem as transactionID*/
		}
		else
			hResult = pIOPCSyncIO->Read(OPC_DS_DEVICE, dwCount, hServerItem, &pValues, &pErrors);

		if (FAILED(hResult) || hResult == S_FALSE)
		{
			_com_error err(hResult);
			LPCTSTR errMsg = err.ErrorMessage();
			_tprintf(_T("Read failed: %s\r\n"), errMsg);

			for (DWORD ii = 0; ii < dwCount; ii++) {
				if (pErrors && pErrors[ii]) {
					if (pErrors[ii] == OPC_E_INVALIDHANDLE) {
						_tprintf(_T("element with index [%d] is invalid\n"), ii);
					}
					else
					{
						_com_error err(pErrors[ii]);
						errMsg = err.ErrorMessage();
						_tprintf(_T("Reading element with index [%d] failed: %s\n"), ii, errMsg);
					}
				}
				else
				{
					if (!async) {
						VARIANT vValue;
						VariantInit(&vValue);

						if (SUCCEEDED(VariantChangeType(&vValue, &pValues[ii].vDataValue, NULL, VT_BSTR))) {

							clientNode* tmpNode = findNode(true, hServerItem[ii]);
							_tprintf(_T("syncoReadWrite Read: %S %S\r\n"), tmpNode->clientName, vValue.bstrVal);
						}

						VariantClear(&vValue);
					}
				}
			}
		}
		else if (!async)
		{
			for (DWORD ii = 0; ii < dwCount; ii++)
			{
				VARIANT vValue;
				VariantInit(&vValue);

				if (SUCCEEDED(VariantChangeType(&vValue, &pValues[ii].vDataValue, NULL, VT_BSTR))) {

					clientNode* tmpNode = findNode(true, hServerItem[ii]);
					_tprintf(_T("syncoReadWrite Read: %S %S\r\n"), tmpNode->clientName, vValue.bstrVal);
				}

				VariantClear(&vValue);
			}
		}

		for (size_t i = 0; i < dwCount; i++) {

			if (!async)
				freeNode(hServerItem[i]);

			free(*(result + i));
		}

		free(result);

		if (!async)
			hResult = serverGroup->groupInfo->ipMgt->RemoveItems(dwCount, hServerItem, &pErrors);

		CoTaskMemFree(pValues);

	}
	else
	{
		_tprintf(_T("Enter tag name and value seperated by comma, and delimit them in semicolon: "));

		fgets(buffer, MAXBYTE, stdin);

		size_t ln = strlen(buffer) - 1;
		if (buffer[ln] == '\n')
			buffer[ln] = '\0';

		char **result = NULL, **nameValuePair = NULL, **names = NULL, **values = NULL;
		size_t dwCount = 0;

		if (strlen(buffer) == 0) {

			_tprintf(_T("tag name/value pair should be in format like this - tagName1, tagValue1; tagName2, tagValue2; tagName3, tagValue3\n"));
			hResult = E_INVALIDARG;

			goto end;
		}

		tokenizeString(buffer, ';', (char***)&result, &dwCount);

		names = (char**)malloc(sizeof(void*)*dwCount);
		values = (char**)malloc(sizeof(void*)*dwCount);

		for (DWORD ii = 0; ii < dwCount; ii++) {
			names[ii] = NULL;
			values[ii] = NULL;
		}
		size_t count = 0;

		for (DWORD ii = 0; ii < dwCount; ii++) {
			tokenizeString(result[ii], ',', (char***)&nameValuePair, &count);

			if (count == 2) {
				names[ii] = nameValuePair[0];
				values[ii] = nameValuePair[1];
			}
			else
			{
				_tprintf(_T("tag name and value should be paired. Check your input.\n"));

				for (size_t i = 0; i < dwCount; i++) {
					free(names[i]);
					free(values[i]);
					free(result[i]);
				}

				free(nameValuePair);

				free(names);
				free(values);
				free(result);

				goto end;
			}
			count = 0;
		}

		pResults = (OPCITEMRESULT*)CoTaskMemAlloc(dwCount * sizeof(OPCITEMRESULT));
		hServerItem = (OPCHANDLE *)CoTaskMemAlloc(dwCount * sizeof(OPCHANDLE));
		pErrors = (HRESULT *)CoTaskMemAlloc(dwCount * sizeof(HRESULT));

		hResult = addItems(serverGroup->groupInfo->ipMgt, names, &pResults, &pErrors, dwCount);

		for (DWORD ii = 0; ii < dwCount; ii++) {
			if (!pErrors[ii])
				hServerItem[ii] = pResults[ii].hServer;
		}

		VARIANT *varValue = (VARIANT *)CoTaskMemAlloc(dwCount * sizeof(VARIANT));
		for (DWORD ii = 0; ii < dwCount; ii++)
		{
			if (!pErrors[ii])
			{
				varValue[ii].vt = VT_R4;
				varValue[ii].fltVal = strtof(values[ii], NULL);
			}
		}

		if (async) {
			DWORD dwCancelID;
			hResult = pIOPCAsyncIO2->Write(dwCount, hServerItem, varValue, *hServerItem, &dwCancelID, &pErrors); /* *hServerItem as transactionID */
		}
		else
			hResult = pIOPCSyncIO->Write(dwCount, hServerItem, varValue, &pErrors);

		if (FAILED(hResult) || hResult == S_FALSE)
		{
			_com_error err(hResult);
			LPCTSTR errMsg = err.ErrorMessage();
			_tprintf(_T("Write failed: %s\r\n"), errMsg);

			for (DWORD ii = 0; ii < dwCount; ii++)
			{
				if (pErrors && pErrors[ii]) {
					if (pErrors[ii] == OPC_E_INVALIDHANDLE)
						_tprintf(_T("element with index [%d] is invalid\n"), ii);
					else {
						_com_error err(pErrors[ii]);
						errMsg = err.ErrorMessage();
						_tprintf(_T("Writing element with index [%d] failed: %s\n"), ii, errMsg);
					}
				}
			}
		}
		else
		{
			_tprintf(_T("Writing is successful.\n"));
		}

		if (!async)
			hResult = serverGroup->groupInfo->ipMgt->RemoveItems(dwCount, hServerItem, &pErrors);

		CoTaskMemFree(varValue);

		for (size_t i = 0; i < dwCount; i++) {
			if (!async)
				freeNode(hServerItem[i]);

			free(names[i]);
			free(values[i]);
			free(*(result + i));
		}

		free(names);
		free(values);
		free(result);
	}

end:
	free(buffer);
	CoTaskMemFree(pResults);
	CoTaskMemFree(hServerItem);
	CoTaskMemFree(pErrors);

	if (pIOPCSyncIO)
		pIOPCSyncIO->Release();
	if (pIOPCAsyncIO2)
		pIOPCAsyncIO2->Release();

	return hResult;
}

程序比较长,大致的结构是这样的。根据传入的是否异步的值,从获得的OPC服务端的实例中取得执行IID_IOPCAsyncIO2(异步)或者IID_IOPCSyncIO(同步)的实例位置,如果是异步还需先告诉OPC服务器你的回调函数是什么,在这里是buildCallback(), 具体程序见下。根据传入的读写值来处理。先进行读的处理,根据异同步分别处理;然后是写的处理,也分异同步进行。当中也有一些辅助函数,我就不一一例举了,有需要的和我联系我再在这里贴出来。客户端打算告一段落,下篇讲讲服务端的安全问题。

HRESULT buildCallback(serverGroup *serverGroup) {
	HRESULT hResult = S_OK;

	hResult = serverGroup->groupInfo->ipMgt->QueryInterface(IID_IConnectionPointContainer, (void**)&serverGroup->groupInfo->ipCPC);

	if (FAILED(hResult))
	{
		_tprintf(_T("QueryInterface for IConnectionPointContainer failed.\r\n"));
		return hResult;
	}

	IConnectionPoint* ipCP = NULL;
	hResult = serverGroup->groupInfo->ipCPC->FindConnectionPoint(IID_IOPCDataCallback, &ipCP);

	if (FAILED(hResult))
	{
		_tprintf(_T("FindConnectionPoint failed.\r\n"));
		return hResult;
	}

	// create the callback object.
	Callback* ipCallback = new Callback();
	DWORD dwAdvise;
	hResult = ipCP->Advise(ipCallback, &dwAdvise);

	if (FAILED(hResult))
	{
		_tprintf(_T("Advise failed.\r\n"));
		return hResult;
	}

	return hResult;
}

 

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
MFC OPC客户端是一个基于MFC(Microsoft Foundation Class)框架开发的OPC(OLE for Process Control)客户端程序。 OPC是一种用于工业自动化中的通信协议,可以实现不同厂家的设备和软件系统之间的数据交换。它提供了一种统一的接口,将不同设备的数据进行封装和取,使得用户能够方便地进行设备监控与控制。 MFC是Microsoft在Windows平台上开发的一套应用程序开发工具集,它提供了许多用于Windows应用程序开发的类库和工具。借助MFC,开发者可以更快速地构建出界面友好、功能强大的应用程序。 MFC OPC客户端充分利用了MFC框架的优势,提供了一套便捷的API接口,使得用户能够快速开发出自己的OPC客户端应用。通过MFC OPC客户端,用户可以连接到OPC服务器,并获取设备的实时数据、历史数据和报警信息等。同时,还可以通过MFC框架中提供的图形界面和控件,方便地实现用户与设备的交互操作。 MFC OPC客户端的开发过程相对简单,开发者只需在MFC应用程序的基础上添加OPC相关代码即可。通过OPC协议,MFC OPC客户端可以与不同厂家的设备进行数据交换,实现设备之间的互联互通。而且,MFC框架提供了丰富的图形界面组件和工具,使得开发者能够更加方便地设计和布局自己的客户端应用。 总之,MFC OPC客户端是基于MFC框架开发的一个用于与OPC服务器进行通信的应用程序。它通过提供便捷的API接口和图形界面组件,使得用户能够快速开发出友好、功能强大的OPC客户端应用,实现设备之间的数据交换与控制。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值