OPC技术是一般是用于PLC和上位机通信的一个基于COM的一个通信组件。好比某个项目是用西门子系列的PLC控制的自动化系统经过西门子的中间件一般会安装S7-200 PC Access或者SimaticNet的OPC服务端软件。这两个软件的目的就是在上位机的系统中搭建了一个OPC Server并提供访问能够编程实现遵循OPC技术使上位机与PLC通信的功能。
此外,须要强调一点,OPC并非西门子的技术,它是一个标准,凡是遵循OPC技术的PLC都能共经过其标准与下位机通信 。
c++
几个关于OPC的概念:
同步读:在调用OPC的接口函数时实时的将数据(组)经过出口参数传出
同步写:在调用OPC的接口函数时实时的将数据写入寄存器
异步读:调用OPC接口不会直接写入PLC寄存器,而是在注册的回调函数中拿到数据的相关信息
异步写:也是在回调函数中将数据写入
组的概念:
组中能够包含项,是多个项的一个集合
组是和OPC提供的IO接口绑定的,OPC的IO接口是用于读写数据
项的概念:
项其实就是对于了PLC上的对应地址,每种OPC服务器根据厂商不一样定义的格式不一样
编程
关于封装的类数组
状况说明(这个类是本人在开发上位机软件与西门子S200系列PLC通讯是所编写的 OPC服务器是SimaticNet)服务器
几个疑惑点说明:异步
OPC服务器提供了几个接口的头文件须要在项目中添加函数
须要加到工程中的文件:this
opc.h 指针
Pre_OPC.hcode
Pre_OPC.cpporm
如下几个文件不用添加到工程中但须要放在工做目录下
opcerror.h
opcda_i.c
opcda.h
opccomn_i.c
opccomn.h
相关文件OPC实现文件(c++)
封装的OPC 操做类
#ifndef OPCRES_H_ #define OPCRES_H_ #include "Pre_OPC.h" #define LOCALE_ID 0x409// Code 0x409 = ENGLISH #define ASYNC 0x01 #define SYNC 0x10 class OPCRes{ public: OPCRes(int SyncItemNum,int AsyncItemNum,IOPCServer *pIOPCServer,HWND hWnd); ~OPCRes(); void UninitRes(); void OPC_AddGroup(LPCWSTR SyncGroupName,LPCWSTR AsyncGroupName); void OPC_AddItem(BOOL IsActive); void OPC_SetItem(DWORD flag,int Order,LPWSTR in_ID,CString Name); void OPC_ReadItem(DWORD flag); int OPC_ReadItem(DWORD flag,CString Name); int OPC_WriteItem(DWORD flag,int Order,int in_Value); void OPC_Subscribe(BOOL IsActiveCheck); DWORD GetAsyncCount(); static void InitCOM(IOPCServer* &pIOPCServer,LPWSTR CLSID_ID);//传递IOPCServer指针类型的引用将外部声明的变量传进来 static void UninitCOM(IOPCServer* &pIOPCServer); private: OPCHANDLE m_GrpSrvHandle; IOPCServer *m_pIOPCServer; IOPCSyncIO *m_pIOPCSyncIO_S;//用于同步访问数据项的同步读写 IOPCSyncIO *m_pIOPCSyncIO_A;//用于异步访问数据项的同步写入 IOPCAsyncIO2 *m_pIOPCAsyncIO2;//用于异步访问数据项的异步读取 IOPCGroupStateMgt *m_pIOPCGroupStateMgt; IOPCItemMgt *m_pIOPCItemMgt[2]; //数据项状态指针1异步0同步 OPCITEMRESULT *m_pAsyncItemResult;//异步数据项返回信息 OPCITEMDEF *m_AsyncItem; //异步数据项指针 CString *m_AsyncItemName; //异步数据项的指定名字 HRESULT *m_pAsyncErrors; //异步数据错误信息 DWORD m_AsyncItemCount; //异步数据项的个数 OPCITEMRESULT *m_pSyncItemResult; //同步数据项返回信息 OPCITEMDEF *m_SyncItem; //同步数据项指针 CString *m_SyncItemName; //同步数据项的指定名字 HRESULT *m_pSyncErrors; //同步数据错误信息 DWORD m_SyncItemCount; //同步数据项的个数 DWORD m_flag; //标记当前对象存在那种类型的数据项 DWORD m_dwAdvise; //用于OPC Server返回的回调接口标识 public: BOOL m_ActiveCheck; int *m_ReadVal_A; //存放异步数据项的值 CString *m_ReadQu_A; //存放异步数据项的品质标签 CString *m_ReadTs_A; //存放异步数据项的时间戳 int *m_ReadVal_S; //存放同步数据项的值 CString *m_ReadQu_S; //存放同步数据项的品质标签 CString *m_ReadTs_S; //存放同步数据项的时间戳 }; #endif //OPCRES_H_
实现
#include "stdafx.h" #include "callback.h" #include "OPCRes.h" CComModule _Module;//必须定义此全局变量不然没法使用COM组件 /***************************************************** 函数名称:构造函数 参数说明: in 一、指定同步组的数据项个数 in 二、指定异步组的数据项个数 in 三、传进窗口类定义的OPC服务接口指针 ******************************************************/ OPCRes::OPCRes(int SyncNum,int AsyncNum,IOPCServer *pIOPCServer) :m_SyncItemCount(SyncNum),m_AsyncItemCount(AsyncNum),m_pIOPCServer(pIOPCServer),m_ActiveCheck(FALSE),m_flag(0x00) { if(!(AsyncNum+SyncNum)) { AfxMessageBox("必须设置监控的数据项",MB_ICONERROR); ExitProcess(0); } if( SyncNum>0 ) { m_flag|=SYNC; m_SyncItem=new OPCITEMDEF[SyncNum];//同步的数据项数组 m_SyncItemName=new CString[SyncNum]; m_ReadVal_S=new int[SyncNum]; m_ReadQu_S=new CString[SyncNum]; m_ReadTs_S=new CString[SyncNum]; } if( AsyncNum>0 ) { m_flag|=ASYNC; m_AsyncItem=new OPCITEMDEF[AsyncNum];//异步的数据项数组 m_AsyncItemName=new CString[AsyncNum]; m_ReadVal_A=new int[AsyncNum]; m_ReadQu_A=new CString[AsyncNum]; m_ReadTs_A=new CString[AsyncNum]; } m_pAsyncItemResult = NULL; m_pSyncItemResult = NULL; } /***************************************************** 函数名称:析构函数 说明: 释放OPC资源 ******************************************************/ OPCRes::~OPCRes() { if( (m_flag&SYNC) == SYNC) { delete[] m_SyncItem; delete[] m_ReadVal_S; delete[] m_ReadQu_S; delete[] m_ReadTs_S; delete[] m_SyncItemName; } if( (m_flag&ASYNC) == ASYNC) { delete[] m_AsyncItem; delete[] m_ReadVal_A; delete[] m_ReadQu_A; delete[] m_ReadTs_A; delete[] m_AsyncItemName; } } /***************************************************** 函数名称:增长数据组 参数说明: in 一、指定同步组名 in 二、指定异步组名 返回值: 无返回值 状况说明: 每一个对象各有一个同步组一个异步组 ******************************************************/ void OPCRes::OPC_AddGroup(LPCWSTR SyncGroupName,LPCWSTR AsyncGroupName) { HRESULT r1; //接收AddGroup函数的返回值用于判断 long TimeBias = 0; //in 与标准时间的校订值 float PercentDeadband = 0.0; //in 要舍弃的数据 DWORD RevisedUpdateRate; //out 服务器的数据刷新率 CString szErrorText; //记录输出信息 //建立同步的数据组 if( (m_flag & SYNC) == SYNC) { //添加组对象并查询IOPCItemMgt接口 r1=m_pIOPCServer->AddGroup(SyncGroupName,FALSE,500,1,&TimeBias,&PercentDeadband,LOCALE_ID,\ &m_GrpSrvHandle,&RevisedUpdateRate,IID_IOPCItemMgt,(LPUNKNOWN*)&m_pIOPCItemMgt[0]); if(r1 == OPC_S_UNSUPPORTEDRATE) { szErrorText.Format ("同步数据组的实际刷新率为%d,与请求值不一样",RevisedUpdateRate ); AfxMessageBox (szErrorText); } else if (FAILED(r1)) { AfxMessageBox("没法建立同步数据组到服务器", MB_OK+MB_ICONERROR); m_pIOPCServer->Release(); m_pIOPCServer = NULL; CoUninitialize(); return; } } //建立异步的数据组 if( (m_flag & ASYNC) == ASYNC) { r1=m_pIOPCServer->AddGroup(AsyncGroupName,FALSE,500,1,&TimeBias,&PercentDeadband,LOCALE_ID,\ &m_GrpSrvHandle,&RevisedUpdateRate,IID_IOPCItemMgt,(LPUNKNOWN*)&m_pIOPCItemMgt[1]); if (r1 == OPC_S_UNSUPPORTEDRATE) { szErrorText.Format ("异步数据组的实际刷新率为%d,与请求值不一样",RevisedUpdateRate ); AfxMessageBox (szErrorText); } else if (FAILED(r1)) { AfxMessageBox("没法建立异步数据组到服务器", MB_OK+MB_ICONERROR); m_pIOPCServer->Release(); m_pIOPCServer = NULL; CoUninitialize(); return; } } } /***************************************************** 函数名称:设置数据项 参数说明: in 一、指定设置同步/异步类型 in 二、指定要设置的数据项序号(数组序) in 三、指定数据项的ID(例如:L"S7:[S7 connection_1]DB1,W4326") in 四、指定数据项的名称(同数据项的序号对应) 返回值: 无 状况说明: 经过参数设置每一个数据项的ID和名字 ******************************************************/ void OPCRes::OPC_SetItem(DWORD flag,int Order,LPWSTR in_ID,CString in_Name) { if(SYNC == flag) { m_SyncItem[Order].szItemID=in_ID; m_SyncItemName[Order]=in_Name; } else if(ASYNC == flag) { m_AsyncItem[Order].szItemID=in_ID; m_AsyncItemName[Order]=in_Name; } else { AfxMessageBox("指定标记错误",MB_ICONERROR); } } /***************************************************** 函数名称:添加数据项 参数说明: 无 返回值: 无返回值 状况说明: 将设置好的数据项添加到组中 ******************************************************/ void OPCRes::OPC_AddItem(BOOL IsActive) { HRESULT r1; //接收AddGroup函数的返回值用于判断 LPWSTR *ErrorStr; //out 存放返回的错误信息字符串 DWORD i; //循环控制 if( (m_flag & SYNC)==SYNC) { for(i=0;i<m_SyncItemCount;i++) { m_SyncItem[i].szAccessPath= L""; //OPC服务器存取路径 m_SyncItem[i].bActive= TRUE; //活动状态 m_SyncItem[i].hClient= i; //操做句柄(主要用于异步项的回调) m_SyncItem[i].dwBlobSize= 0; //pBlob大小 m_SyncItem[i].pBlob= NULL; //二进制指针 m_SyncItem[i].vtRequestedDataType = 2; //数据类型(2:int型) } CString szOut="";//用来输出提示信息 ErrorStr=new LPWSTR[m_SyncItemCount]; r1 = m_pIOPCItemMgt[0]->AddItems(m_SyncItemCount,m_SyncItem,&m_pSyncItemResult,&m_pSyncErrors); if ( (r1 != S_OK) && (r1 != S_FALSE) ) { AfxMessageBox("同步数据项添加失败!", MB_OK+MB_ICONERROR); m_pIOPCItemMgt[0]->Release(); m_pIOPCItemMgt[0] = NULL; m_GrpSrvHandle = 0; m_pIOPCServer->Release(); m_pIOPCServer = NULL; CoUninitialize(); return; } else { for(i=0;i<m_SyncItemCount;i++) { m_pIOPCServer->GetErrorString(m_pSyncErrors[i], LOCALE_ID, &ErrorStr[i]);//获取错误信息 } CString *tempInfo;//存放每个数据项的提示信息 tempInfo=new CString[m_SyncItemCount]; for(i=0;i<m_SyncItemCount;i++) { tempInfo[i].Format("Sync Item%d :%ls\n",i,ErrorStr[i]); szOut+=tempInfo[i];//把每一项的提示信息组合到输出提示字符串中 CoTaskMemFree(ErrorStr[i]); } AfxMessageBox(szOut, MB_OK+MB_ICONINFORMATION); delete[] tempInfo; } //检查数据项的读写性 for(i=0;i<m_SyncItemCount;i++) { if (m_pSyncItemResult[i].dwAccessRights != (OPC_READABLE + OPC_WRITEABLE)) { szOut.Format("同步数据项%d不可读写!\n",i); AfxMessageBox(szOut, MB_OK+MB_ICONEXCLAMATION); } } //查询同步IO接口 r1 = m_pIOPCItemMgt[0]->QueryInterface(IID_IOPCSyncIO,(void**)&m_pIOPCSyncIO_S); if (r1 < 0) { AfxMessageBox("同步接口IOPCSyncIO未找到!", MB_OK+MB_ICONERROR); CoTaskMemFree(m_pAsyncItemResult); m_pIOPCItemMgt[0]->Release(); m_pIOPCItemMgt[0] = 0; m_GrpSrvHandle = 0; m_pIOPCServer->Release(); m_pIOPCServer = NULL; CoUninitialize(); return; } } //添加异步数据项 if( (m_flag & ASYNC) == ASYNC) { for(i=0;i<m_AsyncItemCount;i++) { m_AsyncItem[i].szAccessPath= L""; m_AsyncItem[i].bActive= TRUE; m_AsyncItem[i].hClient= i;//操做句柄(项的序号),在异步回调函数中和参数phClientItems[?]对应 m_AsyncItem[i].dwBlobSize= 0; m_AsyncItem[i].pBlob= NULL; m_AsyncItem[i].vtRequestedDataType = 2; } CString szOut=""; ErrorStr=new LPWSTR[m_AsyncItemCount]; r1 = m_pIOPCItemMgt[1]->AddItems(m_AsyncItemCount,m_AsyncItem,&m_pAsyncItemResult,&m_pAsyncErrors); if ( (r1 != S_OK) && (r1 != S_FALSE) ) { AfxMessageBox("异步数据项添加失败!", MB_OK+MB_ICONERROR); m_pIOPCItemMgt[1]->Release(); m_pIOPCItemMgt[1] = NULL; m_GrpSrvHandle = 0; m_pIOPCServer->Release(); m_pIOPCServer = NULL; CoUninitialize(); return; } else { for(i=0;i<m_AsyncItemCount;i++) { m_pIOPCServer->GetErrorString(m_pAsyncErrors[i], LOCALE_ID, &ErrorStr[i]);//获取错误信息 } CString *tempInfo; tempInfo=new CString[m_AsyncItemCount]; for(i=0;i<m_AsyncItemCount;i++) { tempInfo[i].Format("Async Item%d :%ls\n",i,ErrorStr[i]); szOut+=tempInfo[i]; CoTaskMemFree(ErrorStr[i]); } AfxMessageBox(szOut, MB_OK+MB_ICONINFORMATION); delete[] tempInfo; } //检查数据项的读写性 for(i=0;i<m_AsyncItemCount;i++) { if (m_pAsyncItemResult[i].dwAccessRights != (OPC_READABLE + OPC_WRITEABLE)) { szOut.Format("异步数据项%d不可读写!\n",i); AfxMessageBox(szOut, MB_OK+MB_ICONEXCLAMATION); } } //为了异步组的对象能够同步写入因此也要查询同步接口 r1 = m_pIOPCItemMgt[1]->QueryInterface(IID_IOPCSyncIO,(void**)&m_pIOPCSyncIO_A); if (r1 < 0) { AfxMessageBox("同步接口IOPCSyncIO未找到!", MB_OK+MB_ICONERROR); CoTaskMemFree(m_pAsyncItemResult); m_pIOPCItemMgt[1]->Release(); m_pIOPCItemMgt[1] = 0; m_GrpSrvHandle = 0; m_pIOPCServer->Release(); m_pIOPCServer = NULL; CoUninitialize(); return; } //得到GroupStateMgt组状态接口 r1=m_pIOPCItemMgt[1]->QueryInterface(IID_IOPCGroupStateMgt, (void**)&m_pIOPCGroupStateMgt); if (r1 != S_OK) { AfxMessageBox("组状态接口IOPCGroupStateMgt未找到!", MB_OK+MB_ICONERROR); CoTaskMemFree(m_pAsyncItemResult); m_pIOPCItemMgt[1]->Release(); m_pIOPCItemMgt[1]= 0; m_GrpSrvHandle = 0; m_pIOPCServer->Release(); m_pIOPCServer = NULL; CoUninitialize(); return; } //查询组对象异步接口 r1 = m_pIOPCItemMgt[1]->QueryInterface(IID_IOPCAsyncIO2,(void**)&m_pIOPCAsyncIO2); if (r1 < 0) { AfxMessageBox("异步接口IOPCAsyncIO未找到!", MB_OK+MB_ICONERROR); CoTaskMemFree(m_pAsyncItemResult); m_pIOPCItemMgt[1]->Release(); m_pIOPCItemMgt[1] = 0; m_GrpSrvHandle = 0; m_pIOPCServer->Release(); m_pIOPCServer = NULL; CoUninitialize(); return; } // Activate Group according to Checkbox if(IsActive)//激活订阅 { OPC_Subscribe(IsActive); } // Establish Callback for all Async operations 创建异步回调 CComObject<COPCDataCallback>* pCOPCDataCallback;// Pointer to Callback Object // Create Instance of Callback Object using an ATL template 经过ATL模板建立回调对象的实例 CComObject<COPCDataCallback>::CreateInstance(&pCOPCDataCallback); // pass pointer of this call Object to callback object pCOPCDataCallback->InformAbout(this); // query IUnknown interface of callback object, needed for the ATL Advise 查询IUnknown接口 LPUNKNOWN pCbUnk; pCbUnk = pCOPCDataCallback->GetUnknown(); // Creates a connection between the OPC Server's connection point and // this client's sink (the callback object).创建一个服务器的链接点与客户程序接收器之间的链接 HRESULT hRes = AtlAdvise( m_pIOPCGroupStateMgt, pCbUnk,IID_IOPCDataCallback,&m_dwAdvise ); if (hRes != S_OK) { AfxMessageBox("Advise failed!"); CoTaskMemFree(m_pAsyncItemResult); m_pIOPCItemMgt[1]->Release(); m_pIOPCItemMgt[1] = 0; m_GrpSrvHandle = 0; m_pIOPCServer->Release(); m_pIOPCServer = NULL; CoUninitialize(); return; } } } /***************************************************** 函数名称:读取数据项(全体读取版本) 参数说明: in 一、指定读取的同步/异步组 返回值: 无返回值 状况说明: 此函数将读取指定的组中全部数据项的值 ******************************************************/ //读取一组中全部寄存器的值 void OPCRes::OPC_ReadItem(DWORD flag) { HRESULT r1; //接收ReadItem函数的返回值用于判断 OPCHANDLE *phServer; //in Item的的服务句柄 DWORD dwCancelID; //out 异步读取返回服务器Cancel ID OPCITEMSTATE *pItemValue; //out OPCITEMSTATE结构数组指针(返回同步读取的数据项信息) HRESULT *pErrors; //out 返回的错误指针保存每一项的错误信息编号 LPWSTR *ErrorStr; //用于保存错误编号对应的错误信息内容 CString szOut; //存放输出信息 DWORD i; //控制循环 if(flag==SYNC) { if( (m_flag&SYNC) != SYNC) { AfxMessageBox("同步组不存在!"); return; } for(i=0;i<m_SyncItemCount;i++) { if (m_pSyncErrors[i] != S_OK)//判断Item的可用性 { szOut.Format("OPC Async Item%d not available!",i); AfxMessageBox(szOut, MB_OK+MB_ICONERROR); return; } } phServer = new OPCHANDLE[m_SyncItemCount];// Memory allocation really needed, if more than 1 item to be read for(i=0;i<m_SyncItemCount;i++) { phServer[i] = m_pSyncItemResult[i].hServer;// Select item by server handle, received at AddItem } r1 = m_pIOPCSyncIO_S->Read(OPC_DS_DEVICE,m_SyncItemCount,phServer,&pItemValue,&pErrors); delete[] phServer; ErrorStr=new LPWSTR[m_SyncItemCount]; if(r1 == S_OK) { for (i = 0; i<m_SyncItemCount; i++) { m_ReadVal_S[i]=pItemValue[i].vDataValue.intVal; //GetQualityText(pItemValue[i].wQuality); m_ReadTs_S[i]=COleDateTime(pItemValue[i].ftTimeStamp).Format(); } } if (r1 == S_FALSE) { for(i=0;i<m_SyncItemCount;i++) { m_pIOPCServer->GetErrorString(m_pSyncErrors[i], LOCALE_ID, &ErrorStr[i]); } CString *tempInfo;//存放输出提示信息 tempInfo=new CString[m_SyncItemCount]; for(i;i<m_SyncItemCount;i++) { tempInfo[i].Format("Async Item%d:%ls\n",i,ErrorStr[i]); AfxMessageBox(tempInfo[i], MB_OK+MB_ICONERROR); CoTaskMemFree(ErrorStr[i]); } delete[] tempInfo; } if (FAILED(r1)) { szOut.Format ("Method call IOPCSyncIO::Read failed with error code %x", r1); AfxMessageBox(szOut, MB_OK+MB_ICONERROR); } else { // release [out] parameter in case of not failed CoTaskMemFree(pErrors); CoTaskMemFree(pItemValue); } } if( flag==ASYNC ) { if( (m_flag&ASYNC) != ASYNC) { AfxMessageBox("异步组不存在!"); return; } for(i=0;i<m_AsyncItemCount;i++) { if (m_pAsyncErrors[i] != S_OK) // Item not available { szOut.Format("OPC Async Item%d not available!",i); AfxMessageBox(szOut, MB_OK+MB_ICONERROR); return; } } phServer = new OPCHANDLE[m_AsyncItemCount];// Memory allocation really needed, if more than 1 item to be read for(i=0;i<m_AsyncItemCount;i++) { phServer[i] = m_pAsyncItemResult[i].hServer;// Select item by server handle, received at AddItem } r1 = m_pIOPCAsyncIO2->Read(m_AsyncItemCount,phServer,10,&dwCancelID,&pErrors); delete[] phServer; ErrorStr=new LPWSTR[m_AsyncItemCount]; if (r1 == S_FALSE) { for(i=0;i<m_AsyncItemCount;i++) { m_pIOPCServer->GetErrorString(m_pAsyncErrors[i], LOCALE_ID, &ErrorStr[i]); } CString *tempInfo;//存放输出提示信息 tempInfo=new CString[m_AsyncItemCount]; for(i;i<m_AsyncItemCount;i++) { tempInfo[i].Format("Async Item%d:%ls\n",i,ErrorStr[i]); AfxMessageBox(tempInfo[i], MB_OK+MB_ICONERROR); CoTaskMemFree(ErrorStr[i]); } delete[] tempInfo; } if (FAILED(r1)) { szOut.Format ("Method call IOPCAsyncIO2::Read failed with error code %x", r1); AfxMessageBox(szOut, MB_OK+MB_ICONERROR); } else { // release [out] parameter in case of not failed CoTaskMemFree(pErrors); } } } /***************************************************** 函数名称:读取数据项(指定读取版本) 参数说明: in 一、指定读取的同步/异步组 in 二、指定读取的数据项名称 返回值: 若同步读取成功直接返回数据项的值,异步读取成功:0,失败:-1,指定名称未找到:-2 状况说明: 此函数将读取指定的组中数据项的值 ******************************************************/ int OPCRes::OPC_ReadItem(DWORD flag,CString Name) { HRESULT r1; //接收ReadItem函数的返回值用于判断 OPCHANDLE *phServer; //in Item的的服务句柄 DWORD dwCancelID; //out 异步读取返回服务器Cancel ID OPCITEMSTATE *pItemValue; //out OPCITEMSTATE结构数组指针(返回同步读取的数据项信息) HRESULT *pErrors; //out 返回的错误指针保存每一项的错误信息编号 LPWSTR ErrorStr; //用于保存错误编号对应的错误信息内容 CString szOut; //存放输出信息 DWORD i; //控制循环 if(flag==SYNC) { if( (m_flag&SYNC) != SYNC) { AfxMessageBox("同步组不存在!"); return -1; } for(i=0;i<m_SyncItemCount;i++) { if (m_pSyncErrors[i] != S_OK) // Item not available { szOut.Format("OPC SyncItem[%d] not available!",i); AfxMessageBox(szOut, MB_OK+MB_ICONERROR); return -1; } } for(i=0;i<m_SyncItemCount;i++)//遍历查找 { if( Name==m_SyncItemName[i] ) { phServer=new OPCHANDLE[1]; phServer[0] = m_pSyncItemResult[i].hServer; //AfxMessageBox("找到指定寄存器"); r1 = m_pIOPCSyncIO_S->Read(OPC_DS_DEVICE,1,phServer,&pItemValue,&pErrors); delete[] phServer; if(r1 == S_OK) { return pItemValue[0].vDataValue.intVal;//数值 //GetQualityText(pItemValue[0].wQuality);//品质 //COleDateTime(pItemValue[0].ftTimeStamp).Format();//时间 } if (r1 == S_FALSE) { m_pIOPCServer->GetErrorString(m_pSyncErrors[0], LOCALE_ID, &ErrorStr); CString tempInfo;//存放输出提示信息 tempInfo.Format("%s:%ls\n",m_SyncItemName[i],ErrorStr); AfxMessageBox(tempInfo, MB_OK+MB_ICONERROR); CoTaskMemFree(ErrorStr); return -1; } if (FAILED(r1)) { szOut.Format ("Method call IOPCSyncIO::Read failed with error code %x", r1); AfxMessageBox(szOut, MB_OK+MB_ICONERROR); return -1; } else { // release [out] parameter in case of not failed CoTaskMemFree(pErrors); CoTaskMemFree(pItemValue); return -1; } break; } } return -2;//未找到 } ///////////////////////////////////////////////////////////////////// else if( flag==ASYNC ) { if( (m_flag&ASYNC) != ASYNC) { AfxMessageBox("异步组不存在!"); return -1; } for(i=0;i<m_AsyncItemCount;i++) { if (m_pAsyncErrors[i] != S_OK) // Item not available { szOut.Format("OPC AsyncItem[%d] not available!",i); AfxMessageBox(szOut, MB_OK+MB_ICONERROR); return -1; } } for(i=0;i<m_AsyncItemCount;i++)//遍历查找 { if( Name==m_AsyncItemName[i]) { phServer=new OPCHANDLE[1]; phServer[0] = m_pAsyncItemResult[i].hServer; //AfxMessageBox("找到指定寄存器"); r1 = m_pIOPCAsyncIO2->Read(1,phServer,10,&dwCancelID,&pErrors); delete[] phServer; if (r1 == S_FALSE) { m_pIOPCServer->GetErrorString(m_pSyncErrors[0], LOCALE_ID, &ErrorStr); CString tempInfo;//存放输出提示信息 tempInfo.Format("%s:%ls\n",m_AsyncItemName[i],ErrorStr); AfxMessageBox(tempInfo, MB_OK+MB_ICONERROR); CoTaskMemFree(ErrorStr); return -1; } if (FAILED(r1)) { szOut.Format ("Method call IOPCAsyncIO2::Read failed with error code %x", r1); AfxMessageBox(szOut, MB_OK+MB_ICONERROR); return -1; } else { // release [out] parameter in case of not failed CoTaskMemFree(pErrors); return 0; } } } return -2;//未找到 } else { AfxMessageBox("寄存器标志有误"); return -1; } } /***************************************************** 函数名称:同步写入数据项(指定读取版本) 参数说明: in 一、指定写入的同步/异步组 in 二、指定写入的数据项序号(数组序) in 三、指定写入的数据项值 返回值: 若异步读取成功直接返回数据项的值,同步读取成功:0,失败:-1,指定名称未找到:-2 状况说明: 经过指定组的指定序号向寄存器写入一个值 ******************************************************/ int OPCRes::OPC_WriteItem(DWORD Flag,int Order,int in_Value) { OPCHANDLE *phServer; HRESULT *pErrors; VARIANT values[1]; HRESULT r1; LPWSTR ErrorStr; CString szOut; if(Flag==SYNC) { if( (m_flag&SYNC) != SYNC) { AfxMessageBox("同步组不存在!"); return -1; } for(DWORD i=0;i<m_SyncItemCount;i++) { if (m_pSyncErrors[i] != S_OK) //Item not available { szOut.Format("Sync Item%d not available!",i); AfxMessageBox(szOut, MB_OK+MB_ICONERROR); return -2; } } //Select item by server handle received at AddItem phServer = new OPCHANDLE[1]; phServer[0] = m_pSyncItemResult[Order].hServer; //Set Variant with datatype and received value values[0].vt = VT_I2; values[0].intVal = in_Value; r1 = m_pIOPCSyncIO_S->Write(1, phServer, values, &pErrors); } else if(Flag==ASYNC) { if( (m_flag&ASYNC) != ASYNC) { AfxMessageBox("异步组不存在!"); return -1; } for(DWORD i=0;i<m_AsyncItemCount;i++) { if (m_pAsyncErrors[i] != S_OK) //Item not available { szOut.Format("Async Item%d not available!",i); AfxMessageBox(szOut, MB_OK+MB_ICONERROR); return -2; } } // Select item by server handle received at AddItem phServer = new OPCHANDLE[1]; phServer[0] = m_pAsyncItemResult[Order].hServer; // Set Variant with datatype and received value values[0].vt = VT_I2; values[0].intVal = in_Value; r1 = m_pIOPCSyncIO_A->Write(1, phServer, values, &pErrors); } delete[] phServer; if(r1 == S_OK)//写入成功 { ; } else if (r1 == S_FALSE) { m_pIOPCServer->GetErrorString(pErrors[0], LOCALE_ID, &ErrorStr); szOut.Format("提示:%ls",ErrorStr); AfxMessageBox(szOut); AfxMessageBox("请检查PLC链接"); CoTaskMemFree(pErrors); return -1; } if (FAILED(r1)) { szOut.Format("Method call IOPCSyncIO::Write failed with error code %x", r1); AfxMessageBox(szOut, MB_OK+MB_ICONERROR); return -1; } else { CoTaskMemFree(pErrors); return 0; } } //激活订阅模式 void OPCRes::OPC_Subscribe(BOOL IsActiveCheck) { DWORD dwRevUpdateRate; DWORD dwRequestedUpdateRate=50; FLOAT fPercentDeadband=50; m_ActiveCheck=IsActiveCheck; HRESULT r1=m_pIOPCGroupStateMgt->SetState(&dwRequestedUpdateRate,&dwRevUpdateRate, &m_ActiveCheck, NULL,&fPercentDeadband,NULL,NULL); if (FAILED(r1)) { AfxMessageBox("Set State failed", MB_OK+MB_ICONERROR); return; } } //释放资源 void OPCRes::UninitRes() { HRESULT r1; OPCHANDLE *phServer; if( (m_flag & SYNC) == SYNC) { HRESULT *pErrors; LPWSTR ErrorStr; CString szOut=""; phServer = new OPCHANDLE[m_SyncItemCount]; for(DWORD i=0;i<m_SyncItemCount;i++) { phServer[i] = m_pSyncItemResult[i].hServer; } r1 = m_pIOPCItemMgt[0]->RemoveItems(m_SyncItemCount, phServer, &pErrors); if ( (r1 != S_OK) && (r1 != S_FALSE) ) { AfxMessageBox("Remove SyncItems failed!", MB_OK+MB_ICONERROR); } else { CString tempInfo; for(DWORD i=0;i<m_SyncItemCount;i++) { m_pIOPCServer->GetErrorString(pErrors[i], LOCALE_ID, &ErrorStr); tempInfo.Format("%ls\n",ErrorStr); szOut+=tempInfo; } //AfxMessageBox(szOut, MB_OK+MB_ICONINFORMATION); CoTaskMemFree(ErrorStr); } delete[] phServer; CoTaskMemFree(pErrors); CoTaskMemFree(m_pSyncItemResult); m_pSyncItemResult=NULL; CoTaskMemFree(m_pSyncErrors); m_pSyncErrors = NULL; if(m_SyncItemCount>0)//Release interface for sync calls { m_pIOPCSyncIO_S->Release(); m_pIOPCSyncIO_S = NULL; } if(m_AsyncItemCount>0)//Release interface for Async calls { m_pIOPCSyncIO_A->Release(); m_pIOPCSyncIO_A = NULL; } //Release ItemManagement interface m_pIOPCItemMgt[0]->Release(); m_pIOPCItemMgt[0] = NULL; } if((m_flag & ASYNC) == ASYNC) { LPWSTR ErrorStr; HRESULT *pErrors; CString szOut=""; phServer = new OPCHANDLE[m_AsyncItemCount]; for(DWORD i=0;i<m_AsyncItemCount;i++) { phServer[i] = m_pAsyncItemResult[i].hServer; } r1 = m_pIOPCItemMgt[1]->RemoveItems(m_AsyncItemCount, phServer, &pErrors); if ( (r1 != S_OK) && (r1 != S_FALSE) ) { AfxMessageBox("Remove AsyncItems failed!", MB_OK+MB_ICONERROR); } else { CString tempInfo; for(DWORD i=0;i<m_AsyncItemCount;i++) { m_pIOPCServer->GetErrorString(pErrors[i], LOCALE_ID, &ErrorStr); tempInfo.Format("%ls\n",ErrorStr); szOut+=tempInfo; } //AfxMessageBox(szOut, MB_OK+MB_ICONINFORMATION); CoTaskMemFree(ErrorStr); } delete[] phServer; CoTaskMemFree(pErrors); CoTaskMemFree(m_pAsyncItemResult); m_pAsyncItemResult=NULL; CoTaskMemFree(m_pAsyncErrors); m_pAsyncErrors = NULL; //Release interface for sync calls m_pIOPCAsyncIO2->Release(); m_pIOPCAsyncIO2 = NULL; //Release ItemManagement interface m_pIOPCItemMgt[1]->Release(); m_pIOPCItemMgt[1] = NULL; } //Remove Group r1=m_pIOPCServer->RemoveGroup(m_GrpSrvHandle, TRUE); if (r1 != S_OK) { AfxMessageBox("RemoveGroup failed!", MB_OK+MB_ICONERROR); } m_GrpSrvHandle = NULL; } DWORD OPCRes::GetAsyncCount() { return m_AsyncItemCount; } //初始化COM库,须要在建立类的窗口中经过静态函数调用 //西门子的OPC Server是L"OPC.SimaticNET" void OPCRes::InitCOM(IOPCServer* &pIOPCServer,LPWSTR CLSID_ID)//传递一个IOPCServer*类型的引用即实参自己 { HRESULT r1; CLSID clsid; CString szErrorText; // Initialize the COM library r1 = CoInitialize(NULL); if (r1 != S_OK) { if (r1 == S_FALSE) { //AfxMessageBox("COM Library already initialized",MB_OK+MB_ICONEXCLAMATION); } else { szErrorText.Format("Initialisation of COM Library failed. ErrorCode= %4x", r1); AfxMessageBox(szErrorText, MB_OK+MB_ICONERROR); return; } } // Given a ProgID, this looks up the associated CLSID in the registry r1 = CLSIDFromProgID(CLSID_ID,&clsid); if (r1 != S_OK) { AfxMessageBox("Retrival of CLSID failed", MB_OK+MB_ICONERROR); CoUninitialize(); return; } // Create the OPC server object and querry for the IOPCServer interface of the object r1 = CoCreateInstance (clsid, NULL, CLSCTX_LOCAL_SERVER ,IID_IOPCServer,(void**)&pIOPCServer); if (r1 != S_OK) { AfxMessageBox("Creation of IOPCServer-Object failed", MB_OK+MB_ICONERROR); pIOPCServer = NULL; CoUninitialize(); return; } } //释放COM库 void OPCRes::UninitCOM(IOPCServer* &pIOPCServer) { //Release OPC-Server pIOPCServer->Release(); pIOPCServer = NULL; //Uninit COM CoUninitialize(); }