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;
}

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值