OPC客户端的开发相对来说,只要掌握了OPC基类的几个接口,并知道它们是如何运作的,那么开发起来还是相对容易的。好了,废话不多说了,我们开始吧。
首先是对头文件的引用:
- #include "stdafx.h"
- #include <afxcoll.h>
- #include <iostream>
- #include "opccomn.h"
- #include "opcda.h"
- #include "opcerror.h"
- #include "OPCEnum.h"
- #include "opccomn_i.c"
- #include "opcda_i.c"
- #include "OPCEnum_i.c"
- using namespace std;
- //#include "COPCDataCallback.h" //这里是我在OPC中以数据订阅读取数据而加以引用的,后面会提到
#include "stdafx.h"
#include <afxcoll.h>
#include <iostream>
#include "opccomn.h"
#include "opcda.h"
#include "opcerror.h"
#include "OPCEnum.h"
#include "opccomn_i.c"
#include "opcda_i.c"
#include "OPCEnum_i.c"
using namespace std;
//#include "COPCDataCallback.h" //这里是我在OPC中以数据订阅读取数据而加以引用的,后面会提到
然后是初始化变量:
- HRESULT hr;
- COSERVERINFO si;
- ZeroMemory(&si, sizeof(si)); //内存1 存放服务器信息
- MULTI_QI mqi[1];
- ZeroMemory(&mqi, sizeof(mqi)); //内存2 存放MULTI_QI用以获取OPC服务器列表
- CATID catID[2];
- ZeroMemory(&catID, 2 * sizeof(CATID)); //内存3 存放OPC标准接口1.0和2.0
- CLSID clsid[20];
- ZeroMemory(&clsid, 20 * sizeof(CLSID)); //内存4 存放枚举出的OPC服务器的CLSID
- /*Initialize DCOM*/
- CString strError;
- CString strNode = _T("192.168.x.xx"); //The IP Address of the OPC SERVER
- CString strProgID = _T("xxxxxx"); //The ProgID of the OPC SERVER
- /*初始化指针*/
- IOPCServerList *pIServerList = NULL; //第一个接口指针,指向OPC服务器列表
- IEnumGUID *pIEnumGUID = NULL; //第二个接口指针,指向OPC服务器列表枚举
- IUnknown *pIUnknown = NULL; //第三个指针,服务器接口指针
- IOPCServer *pIServer = NULL; //第四个指针,指向OPC服务器的接口指针
- //IOPCItemMgt *pIOPCItemMgt = NULL; //第五个指针,指向标签的指针
- //OPCITEMDEF *itemArray = NULL; //第六个指针,指向标签内容数组
- //OPCITEMRESULT *pItemResult = NULL; //第七个指针,指向添加项的结果
- //HRESULT *pErrors = NULL; //第八个指针,指向添加项错误
- //OPCHANDLE *hOPCServer2 = NULL; //第九个指针,指向第二个OPCServer句柄
- //IOPCAsyncIO2 *pIOPCAsyncIO2 = NULL; /*第十一个指针,指向异步读取*/
- //IOPCGroupStateMgt *pIOPCGroupStateMgt = NULL; //第十个指针,指向组状态更新</span><pre name="code" class="cpp">//IConnectionPointContainer *pIConnectPointContainer = NULL;
- //IConnectionPoint *pIConnectionPoint = NULL;
HRESULT hr;
COSERVERINFO si;
ZeroMemory(&si, sizeof(si)); //内存1 存放服务器信息
MULTI_QI mqi[1];
ZeroMemory(&mqi, sizeof(mqi)); //内存2 存放MULTI_QI用以获取OPC服务器列表
CATID catID[2];
ZeroMemory(&catID, 2 * sizeof(CATID)); //内存3 存放OPC标准接口1.0和2.0
CLSID clsid[20];
ZeroMemory(&clsid, 20 * sizeof(CLSID)); //内存4 存放枚举出的OPC服务器的CLSID
/*Initialize DCOM*/
CString strError;
CString strNode = _T("192.168.x.xx"); //The IP Address of the OPC SERVER
CString strProgID = _T("xxxxxx"); //The ProgID of the OPC SERVER
/*初始化指针*/
IOPCServerList *pIServerList = NULL; //第一个接口指针,指向OPC服务器列表
IEnumGUID *pIEnumGUID = NULL; //第二个接口指针,指向OPC服务器列表枚举
IUnknown *pIUnknown = NULL; //第三个指针,服务器接口指针
IOPCServer *pIServer = NULL; //第四个指针,指向OPC服务器的接口指针
//IOPCItemMgt *pIOPCItemMgt = NULL; //第五个指针,指向标签的指针
//OPCITEMDEF *itemArray = NULL; //第六个指针,指向标签内容数组
//OPCITEMRESULT *pItemResult = NULL; //第七个指针,指向添加项的结果
//HRESULT *pErrors = NULL; //第八个指针,指向添加项错误
//OPCHANDLE *hOPCServer2 = NULL; //第九个指针,指向第二个OPCServer句柄
//IOPCAsyncIO2 *pIOPCAsyncIO2 = NULL; /*第十一个指针,指向异步读取*/
//IOPCGroupStateMgt *pIOPCGroupStateMgt = NULL; //第十个指针,指向组状态更新</span><pre name="code" class="cpp">//IConnectionPointContainer *pIConnectPointContainer = NULL;
//IConnectionPoint *pIConnectionPoint = NULL;
紧接着进行组件注册,因为OPC是使用COM组件开发的,所以部分过程与组件开发类似:
- /*COM组件注册及登陆*/
- hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); //注册DCOM组件,获取结果
- HRESULT hr_sec = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
- ASSERT(hr_sec == S_OK || RPC_E_TOO_LATE == hr_sec);</span><pre name="code" class="cpp">
/*COM组件注册及登陆*/
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); //注册DCOM组件,获取结果
HRESULT hr_sec = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
ASSERT(hr_sec == S_OK || RPC_E_TOO_LATE == hr_sec);</span><pre name="code" class="cpp">
- if (FAILED(hr)) {
- cout << "未开启COM组件注册..." << endl;
- return 1;
- }
- else if (SUCCEEDED(hr)) {
- cout << "已开启COM组件注册..." << endl;
- cout << "已登陆COM组件..." << endl;
- }
if (FAILED(hr)) {
cout << "未开启COM组件注册..." << endl;
return 1;
}
else if (SUCCEEDED(hr)) {
cout << "已开启COM组件注册..." << endl;
cout << "已登陆COM组件..." << endl;
}
然后获取服务器列表,用到了OPCEnum.exe:
- si.pwszName = (LPWSTR)(strNode.GetString()); //Covert CString to LPWSTR 把服务器名转为宽字节字符串
- mqi[0].hr = S_OK;
- mqi[0].pIID = &IID_IOPCServerList;
- mqi[0].pItf = NULL;
- hr = CoCreateInstanceEx(CLSID_OpcServerList, NULL, CLSCTX_ALL, &si, 1, mqi); //Connect to the target OPC SERVER & Get the target SERVER's OPC SERVER List
- if (FAILED(hr)) {
- cout << "获取目标服务器端OPC服务器列表失败..." << endl;
- }
- else if (SUCCEEDED(hr)) {
- cout << "获取目标服务器端OPC服务器列表成功..." << endl;
- }
si.pwszName = (LPWSTR)(strNode.GetString()); //Covert CString to LPWSTR 把服务器名转为宽字节字符串
mqi[0].hr = S_OK;
mqi[0].pIID = &IID_IOPCServerList;
mqi[0].pItf = NULL;
hr = CoCreateInstanceEx(CLSID_OpcServerList, NULL, CLSCTX_ALL, &si, 1, mqi); //Connect to the target OPC SERVER & Get the target SERVER's OPC SERVER List
if (FAILED(hr)) {
cout << "获取目标服务器端OPC服务器列表失败..." << endl;
}
else if (SUCCEEDED(hr)) {
cout << "获取目标服务器端OPC服务器列表成功..." << endl;
}
进行具有OPC1.0和OPC2.0接口标准的OPC服务器的枚举:
- pIServerList = (IOPCServerList*)mqi[0].pItf; //得到第一个指针
- ASSERT(pIServerList);
- catID[0] = CATID_OPCDAServer10;
- catID[1] = CATID_OPCDAServer20;
- hr = pIServerList->EnumClassesOfCategories(2, catID, 2, catID, &pIEnumGUID); //Enum OPCDASERVER1.0 & OPCDASERVER2.0 得到第二个指针
- ASSERT(pIEnumGUID);
- if (FAILED(hr)) {
- cout << "未获取到OPCDAServer1.0和OPCDAServer2.0接口" << endl;
- CoTaskMemFree(&catID); //第三个内存释放
- CoTaskMemFree(&mqi); //第二个内存释放
- CoTaskMemFree(&si); //第一个内存释放
- if (pIEnumGUID) pIEnumGUID->Release(); //第二个指针释放
- pIEnumGUID = NULL;
- if (pIServerList) pIServerList->Release(); //第一个指针释放
- pIServerList = NULL;
- return 1;
- }
- else if (SUCCEEDED(hr)) {
- cout << "已获取到OPCDAServer1.0和OPCDAServer2.0接口" << endl;
- }
- ULONG nCount;
- HRESULT hr_1;
- cout << "搜索到的接口列表:" << endl;
- do
- {
- hr_1 = pIEnumGUID->Next(20, clsid, &nCount);
- for (ULONG i = 0; i < nCount; i++)
- {
- LPOLESTR szProID;
- LPOLESTR szUserType;
- HRESULT hr_2 = pIServerList->GetClassDetails(clsid[i], &szProID, &szUserType);
- ASSERT(hr_2 == S_OK);
- wcout << szProID << endl;
- CoTaskMemFree(szProID);
- CoTaskMemFree(szUserType);
- }
- } while (hr_1 == S_OK);
- cout << "枚举完毕..." << endl;
pIServerList = (IOPCServerList*)mqi[0].pItf; //得到第一个指针
ASSERT(pIServerList);
catID[0] = CATID_OPCDAServer10;
catID[1] = CATID_OPCDAServer20;
hr = pIServerList->EnumClassesOfCategories(2, catID, 2, catID, &pIEnumGUID); //Enum OPCDASERVER1.0 & OPCDASERVER2.0 得到第二个指针
ASSERT(pIEnumGUID);
if (FAILED(hr)) {
cout << "未获取到OPCDAServer1.0和OPCDAServer2.0接口" << endl;
CoTaskMemFree(&catID); //第三个内存释放
CoTaskMemFree(&mqi); //第二个内存释放
CoTaskMemFree(&si); //第一个内存释放
if (pIEnumGUID) pIEnumGUID->Release(); //第二个指针释放
pIEnumGUID = NULL;
if (pIServerList) pIServerList->Release(); //第一个指针释放
pIServerList = NULL;
return 1;
}
else if (SUCCEEDED(hr)) {
cout << "已获取到OPCDAServer1.0和OPCDAServer2.0接口" << endl;
}
ULONG nCount;
HRESULT hr_1;
cout << "搜索到的接口列表:" << endl;
do
{
hr_1 = pIEnumGUID->Next(20, clsid, &nCount);
for (ULONG i = 0; i < nCount; i++)
{
LPOLESTR szProID;
LPOLESTR szUserType;
HRESULT hr_2 = pIServerList->GetClassDetails(clsid[i], &szProID, &szUserType);
ASSERT(hr_2 == S_OK);
wcout << szProID << endl;
CoTaskMemFree(szProID);
CoTaskMemFree(szUserType);
}
} while (hr_1 == S_OK);
cout << "枚举完毕..." << endl;
然后进行OPC的连接:
- CLSID clsid_citect;
- hr = pIServerList->CLSIDFromProgID(strProgID, &clsid_citect); //获取OPC服务器的CLSID
- if (FAILED(hr)) {
- cout << "未找到需要连接的OPC服务器..." << endl;
- CoTaskMemFree(&clsid); //第四个内存释放
- CoTaskMemFree(&catID); //第三个内存释放
- CoTaskMemFree(&mqi); //第二个内存释放
- CoTaskMemFree(&si); //第一个内存释放
- if (pIEnumGUID) pIEnumGUID->Release(); //第二个指针释放
- pIEnumGUID = NULL;
- if (pIServerList) pIServerList->Release(); //第一个指针释放
- pIServerList = NULL;
- return 1;
- }
- else if (SUCCEEDED(hr)) {
- cout << "已找到需要连接的OPC服务器..." << endl;
- }
- mqi[0].hr = S_OK;
- mqi[0].pIID = &IID_IOPCServer;
- mqi[0].pItf = NULL;
- hr = CoCreateInstanceEx(clsid_citect, NULL, CLSCTX_ALL, &si, 1, mqi);
- if (FAILED(hr)) {
- cout << "未连接上需要连接的OPC服务器..." << endl;
- CoTaskMemFree(&clsid); //第四个内存释放
- CoTaskMemFree(&catID); //第三个内存释放
- CoTaskMemFree(&mqi); //第二个内存释放
- CoTaskMemFree(&si); //第一个内存释放
- if (pIEnumGUID) pIEnumGUID->Release(); //第二个指针释放
- pIEnumGUID = NULL;
- if (pIServerList) pIServerList->Release(); //第一个指针释放
- pIServerList = NULL;
- return 1;
- }
- else if (SUCCEEDED(hr)) {
- cout << "已连接上需要连接的OPC服务器..." << endl;
- }
CLSID clsid_citect;
hr = pIServerList->CLSIDFromProgID(strProgID, &clsid_citect); //获取OPC服务器的CLSID
if (FAILED(hr)) {
cout << "未找到需要连接的OPC服务器..." << endl;
CoTaskMemFree(&clsid); //第四个内存释放
CoTaskMemFree(&catID); //第三个内存释放
CoTaskMemFree(&mqi); //第二个内存释放
CoTaskMemFree(&si); //第一个内存释放
if (pIEnumGUID) pIEnumGUID->Release(); //第二个指针释放
pIEnumGUID = NULL;
if (pIServerList) pIServerList->Release(); //第一个指针释放
pIServerList = NULL;
return 1;
}
else if (SUCCEEDED(hr)) {
cout << "已找到需要连接的OPC服务器..." << endl;
}
mqi[0].hr = S_OK;
mqi[0].pIID = &IID_IOPCServer;
mqi[0].pItf = NULL;
hr = CoCreateInstanceEx(clsid_citect, NULL, CLSCTX_ALL, &si, 1, mqi);
if (FAILED(hr)) {
cout << "未连接上需要连接的OPC服务器..." << endl;
CoTaskMemFree(&clsid); //第四个内存释放
CoTaskMemFree(&catID); //第三个内存释放
CoTaskMemFree(&mqi); //第二个内存释放
CoTaskMemFree(&si); //第一个内存释放
if (pIEnumGUID) pIEnumGUID->Release(); //第二个指针释放
pIEnumGUID = NULL;
if (pIServerList) pIServerList->Release(); //第一个指针释放
pIServerList = NULL;
return 1;
}
else if (SUCCEEDED(hr)) {
cout << "已连接上需要连接的OPC服务器..." << endl;
}
如此,OPC服务器已连接上。