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