注:
1、博主地址为https://blog.csdn.net/u014801367/article/details/43309231
2、博主的opc系列文章和我们软件IOServer通过opc方式采集数据机制完全一样,可作为学习参考用
笔者博客里曾经转载过一篇关于OPC同步读取、异步读取和OPC订阅的区别的博客,其中讲的比较详细,笔者就不再过多的赘述这些内容,总之,同步读取是客户端在发出读取请求之后,需要等待服务器的响应,服务器给出回应之后,客户端才能够进行下一步的操作,而异步读取时,客户端发出请求之后,立马执行下一步的程序,当服务器给出回应之后,客户端才进行读取数据的操作。
总而言之,同步读取读取的结果直接在主程序中存入了数组中,而异步读取的结果是通过一个IOPCDataCallback的类中,有一个继承的方法叫OnReadComplete,异步读取的结果就从这个方法中返回。而这个IOPCDataCallback的类往往是用来进行OPC的数据订阅方法的读取的,所以说,数据订阅往往伴随着异步读取的方式。
下面就来看同步读取的代码。
首先是获取数据项服务句柄:
- hOPCServer2[0] = (OPCHANDLE)pItemResult[0].hServer;
然后是获取同步读取指针IOPCSyncIO,注意不是IOPCAsyncIO,笔者之前就是把这个接口搞错了,所以一直没有获取到数据。根据笔者的印象,前者应该是后者的升级,好像是在OPC2.0接口中才有的。
- IOPCSyncIO *pIOPCSyncIO = NULL; //第十个指针,指向同步读取
- hr = pIOPCItemMgt->QueryInterface(IID_IOPCSyncIO, /*OUT*/ (void**)&pIOPCSyncIO);
- if (FAILED(hr)) {
- cout << "未能获取到接口IOPCSyncIO" << endl;
- if (pItemResult) CoTaskMemFree(pItemResult);
- if (pErrors) CoTaskMemFree(pErrors);
- if (pIOPCSyncIO) CoTaskMemFree(pIOPCSyncIO);
- CoTaskMemFree(&hOPCServer1);
- CoTaskMemFree(&hOPCServer2);
- if (pIServer) pIServer->Release();
- pIServer = NULL;
- if (pIUnknown) pIUnknown->Release();
- pIUnknown = NULL;
- if (pIEnumGUID) pIEnumGUID->Release();
- pIEnumGUID = NULL;
- if (pIServerList) pIServerList->Release();
- pIServerList = NULL;
- if (pIOPCItemMgt) pIOPCItemMgt->Release();
- pIOPCItemMgt = NULL;
- return 1;
- }
- else if (SUCCEEDED(hr)) {
- ASSERT(pIOPCSyncIO);
- cout << "已获取到接口IOPCSyncIO" << endl;
- }
同步读取的代码:
- DWORD dwItemNumber = 1;
- OPCITEMSTATE *pItemValue = NULL; //第十二个指针,指向读取OPC SERVER的值
- hr = pIOPCSyncIO->Read(OPC_DS_CACHE, dwItemNumber, hOPCServer2, &pItemValue, &pErrors);
- if (FAILED(hr))
- {
- cout << "未能读取到OPC服务器端相对应的数据,请查看数据源是否有误" << endl;
- if (pItemResult) CoTaskMemFree(pItemResult);
- if (pErrors) CoTaskMemFree(pErrors);
- if (pIOPCSyncIO) CoTaskMemFree(pIOPCSyncIO);
- CoTaskMemFree(&hOPCServer1);
- CoTaskMemFree(&hOPCServer2);
- CoTaskMemFree(&pItemValue);
- if (pIServer) pIServer->Release();
- pIServer = NULL;
- if (pIUnknown) pIUnknown->Release();
- pIUnknown = NULL;
- if (pIEnumGUID) pIEnumGUID->Release();
- pIEnumGUID = NULL;
- if (pIServerList) pIServerList->Release();
- pIServerList = NULL;
- if (pIOPCItemMgt) pIOPCItemMgt->Release();
- pIOPCItemMgt = NULL;
- VariantClear(&pItemValue[0].vDataValue);
- return 1; //同步读数据时出错
- }
- else if (SUCCEEDED(hr)){
- ASSERT(hr);
- cout << "已读取到OPC服务器端的数据" << endl;
- cout << V_R4(&pItemValue[0].vDataValue) << endl; //输出数据
- }
异步读取其实与同步读取类似,异步读取需要获取的接口是IOPCAsyncIO2,注意不是IOPCSyncIO2,IOPCSyncIO2是IOPCAsyncIO2的升级。
- hr = pIOPCItemMgt->QueryInterface(IID_IOPCAsyncIO2, /*OUT*/(void**)&pIOPCAsyncIO2); //得到第十一个指针
- ASSERT(pIOPCAsyncIO2);
- if (FAILED(hr)) {
- cout << "未能获取到接口IOPCSyncIO2..." << endl;
- if (pItemResult) CoTaskMemFree(pItemResult);
- if (pErrors) CoTaskMemFree(pErrors);
- CoTaskMemFree(&hOPCServer1);
- CoTaskMemFree(&hOPCServer2); //第六个内存释放
- CoTaskMemFree(&itemArray); //第五个内存释放
- CoTaskMemFree(&clsid); //第四个内存释放
- CoTaskMemFree(&catID); //第三个内存释放
- CoTaskMemFree(&mqi); //第二个内存释放
- CoTaskMemFree(&si); //第一个内存释放
- if (pIOPCAsyncIO2) pIOPCAsyncIO2->Release(); //第十一个指针释放
- pIOPCAsyncIO2 = NULL;
- 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 << "已获取到接口IOPCSyncIO2..." << endl;
- }
异步读取的代码:
- DWORD dwItemNumber = 1;
- DWORD dwCancelID;
- OPCITEMSTATE *pItemValue = NULL; //第十二个指针,指向读取OPC SERVER的值
- hr = pIOPCAsyncIO2->Read(dwItemNumber, hOPCServer2, 1, &dwCancelID, &pErrors); //异步读取,数据在COPCDataCallback中返回
- if (FAILED(hr)) {
- cout << "未能读取到OPC服务器端相对应的数据,请查看数据源是否有误..." << endl;
- VariantClear(&pItemValue[0].vDataValue);
- if (pItemResult) CoTaskMemFree(pItemResult);
- if (pErrors) CoTaskMemFree(pErrors);
- CoTaskMemFree(&hOPCServer1);
- CoTaskMemFree(&hOPCServer2); //第六个内存释放
- CoTaskMemFree(&itemArray); //第五个内存释放
- CoTaskMemFree(&clsid); //第四个内存释放
- CoTaskMemFree(&catID); //第三个内存释放
- CoTaskMemFree(&mqi); //第二个内存释放
- CoTaskMemFree(&si); //第一个内存释放
- if (pIOPCAsyncIO2) pIOPCAsyncIO2->Release(); //第十一个指针释放
- pIOPCAsyncIO2 = NULL;
- 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 << "已获取到数据..." << endl;
- }
异步读取的结果返回将在下一篇介绍数据订阅读取方式时再做介绍。