OPC客户端开发之OPC服务器的枚举和连接------OPC(第五篇)

    OPC客户端的开发相对来说,只要掌握了OPC基类的几个接口,并知道它们是如何运作的,那么开发起来还是相对容易的。好了,废话不多说了,我们开始吧。

    首先是对头文件的引用:

  1. #include "stdafx.h"  
  2. #include <afxcoll.h>  
  3. #include <iostream>  
  4. #include "opccomn.h"  
  5. #include "opcda.h"  
  6.   
  7. #include "opcerror.h"  
  8. #include "OPCEnum.h"  
  9.   
  10. #include "opccomn_i.c"  
  11. #include "opcda_i.c"  
  12. #include "OPCEnum_i.c"  
  13. using namespace std;  
  14. //#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中以数据订阅读取数据而加以引用的,后面会提到

    然后是初始化变量:

  1. HRESULT hr;  
  2. COSERVERINFO si;  
  3. ZeroMemory(&si, sizeof(si)); //内存1 存放服务器信息  
  4. MULTI_QI mqi[1];  
  5. ZeroMemory(&mqi, sizeof(mqi)); //内存2 存放MULTI_QI用以获取OPC服务器列表  
  6. CATID catID[2];  
  7. ZeroMemory(&catID, 2 * sizeof(CATID));  //内存3 存放OPC标准接口1.0和2.0  
  8. CLSID clsid[20];  
  9. ZeroMemory(&clsid, 20 * sizeof(CLSID)); //内存4 存放枚举出的OPC服务器的CLSID  
  10.   
  11. /*Initialize DCOM*/  
  12. CString strError;  
  13. CString strNode = _T("192.168.x.xx"); //The IP Address of the OPC SERVER  
  14. CString strProgID = _T("xxxxxx");  //The ProgID of the OPC SERVER     
  15.   
  16. /*初始化指针*/  
  17. IOPCServerList *pIServerList = NULL;  //第一个接口指针,指向OPC服务器列表  
  18. IEnumGUID *pIEnumGUID = NULL; //第二个接口指针,指向OPC服务器列表枚举  
  19. IUnknown *pIUnknown = NULL; //第三个指针,服务器接口指针  
  20. IOPCServer *pIServer = NULL; //第四个指针,指向OPC服务器的接口指针  
  21. //IOPCItemMgt *pIOPCItemMgt = NULL; //第五个指针,指向标签的指针  
  22. //OPCITEMDEF *itemArray = NULL; //第六个指针,指向标签内容数组  
  23. //OPCITEMRESULT *pItemResult = NULL;  //第七个指针,指向添加项的结果  
  24. //HRESULT *pErrors = NULL; //第八个指针,指向添加项错误  
  25. //OPCHANDLE *hOPCServer2 = NULL; //第九个指针,指向第二个OPCServer句柄  
  26. //IOPCAsyncIO2 *pIOPCAsyncIO2 = NULL; /*第十一个指针,指向异步读取*/  
  27. //IOPCGroupStateMgt *pIOPCGroupStateMgt = NULL; //第十个指针,指向组状态更新</span><pre name="code" class="cpp">//IConnectionPointContainer *pIConnectPointContainer = NULL;  
  28. //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组件开发的,所以部分过程与组件开发类似: 
 

  1. /*COM组件注册及登陆*/  
  2. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); //注册DCOM组件,获取结果  
  3. HRESULT hr_sec = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);  
  4. 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">
  1. if (FAILED(hr)) {  
  2.     cout << "未开启COM组件注册..." << endl;  
  3.     return 1;  
  4. }  
  5. else if (SUCCEEDED(hr)) {         
  6.     cout << "已开启COM组件注册..." << endl;  
  7.     cout << "已登陆COM组件..." << endl;  
  8. }  
if (FAILED(hr)) {
	cout << "未开启COM组件注册..." << endl;
	return 1;
}
else if (SUCCEEDED(hr)) {		
	cout << "已开启COM组件注册..." << endl;
	cout << "已登陆COM组件..." << endl;
}

 
     然后获取服务器列表,用到了OPCEnum.exe: 
 

  1. si.pwszName = (LPWSTR)(strNode.GetString()); //Covert CString to LPWSTR 把服务器名转为宽字节字符串     
  2.   
  3. mqi[0].hr = S_OK;  
  4. mqi[0].pIID = &IID_IOPCServerList;  
  5. mqi[0].pItf = NULL;  
  6.   
  7. hr = CoCreateInstanceEx(CLSID_OpcServerList, NULL, CLSCTX_ALL, &si, 1, mqi); //Connect to the target OPC SERVER & Get the target SERVER's OPC SERVER List  
  8.   
  9. if (FAILED(hr)) {  
  10.     cout << "获取目标服务器端OPC服务器列表失败..." << endl;  
  11. }  
  12. else if (SUCCEEDED(hr)) {  
  13.     cout << "获取目标服务器端OPC服务器列表成功..." << endl;  
  14. }  
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服务器的枚举:

  1. pIServerList = (IOPCServerList*)mqi[0].pItf; //得到第一个指针  
  2. ASSERT(pIServerList);  
  3.       
  4. catID[0] = CATID_OPCDAServer10;  
  5. catID[1] = CATID_OPCDAServer20;  
  6.       
  7. hr = pIServerList->EnumClassesOfCategories(2, catID, 2, catID, &pIEnumGUID); //Enum OPCDASERVER1.0 & OPCDASERVER2.0 得到第二个指针  
  8. ASSERT(pIEnumGUID);  
  9.   
  10. if (FAILED(hr)) {  
  11.     cout << "未获取到OPCDAServer1.0和OPCDAServer2.0接口" << endl;  
  12.     CoTaskMemFree(&catID); //第三个内存释放  
  13.     CoTaskMemFree(&mqi); //第二个内存释放  
  14.     CoTaskMemFree(&si); //第一个内存释放  
  15.     if (pIEnumGUID) pIEnumGUID->Release(); //第二个指针释放  
  16.     pIEnumGUID = NULL;  
  17.     if (pIServerList) pIServerList->Release(); //第一个指针释放  
  18.     pIServerList = NULL;  
  19.     return 1;  
  20. }  
  21. else if (SUCCEEDED(hr)) {  
  22.     cout << "已获取到OPCDAServer1.0和OPCDAServer2.0接口" << endl;  
  23. }  
  24.   
  25. ULONG nCount;  
  26.       
  27. HRESULT hr_1;  
  28. cout << "搜索到的接口列表:" << endl;  
  29. do  
  30. {  
  31.     hr_1 = pIEnumGUID->Next(20, clsid, &nCount);  
  32.     for (ULONG i = 0; i < nCount; i++)  
  33.     {  
  34.         LPOLESTR szProID;  
  35.         LPOLESTR szUserType;  
  36.         HRESULT hr_2 = pIServerList->GetClassDetails(clsid[i], &szProID, &szUserType);  
  37.         ASSERT(hr_2 == S_OK);  
  38.         wcout << szProID << endl;  
  39.         CoTaskMemFree(szProID);  
  40.         CoTaskMemFree(szUserType);  
  41.     }  
  42. while (hr_1 == S_OK);  
  43. 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的连接:

  1. CLSID clsid_citect;  
  2.   
  3. hr = pIServerList->CLSIDFromProgID(strProgID, &clsid_citect); //获取OPC服务器的CLSID  
  4.   
  5. if (FAILED(hr)) {  
  6.     cout << "未找到需要连接的OPC服务器..." << endl;  
  7.     CoTaskMemFree(&clsid); //第四个内存释放  
  8.     CoTaskMemFree(&catID); //第三个内存释放  
  9.     CoTaskMemFree(&mqi); //第二个内存释放  
  10.     CoTaskMemFree(&si); //第一个内存释放  
  11.     if (pIEnumGUID) pIEnumGUID->Release(); //第二个指针释放  
  12.     pIEnumGUID = NULL;  
  13.     if (pIServerList) pIServerList->Release(); //第一个指针释放  
  14.     pIServerList = NULL;  
  15.     return 1;  
  16. }  
  17. else if (SUCCEEDED(hr)) {  
  18.     cout << "已找到需要连接的OPC服务器..." << endl;  
  19. }  
  20.   
  21. mqi[0].hr = S_OK;  
  22. mqi[0].pIID = &IID_IOPCServer;  
  23. mqi[0].pItf = NULL;  
  24.   
  25. hr = CoCreateInstanceEx(clsid_citect, NULL, CLSCTX_ALL, &si, 1, mqi);  
  26.   
  27. if (FAILED(hr)) {  
  28.     cout << "未连接上需要连接的OPC服务器..." << endl;  
  29.     CoTaskMemFree(&clsid); //第四个内存释放  
  30.     CoTaskMemFree(&catID); //第三个内存释放  
  31.     CoTaskMemFree(&mqi); //第二个内存释放  
  32.     CoTaskMemFree(&si); //第一个内存释放  
  33.     if (pIEnumGUID) pIEnumGUID->Release(); //第二个指针释放  
  34.     pIEnumGUID = NULL;  
  35.     if (pIServerList) pIServerList->Release(); //第一个指针释放  
  36.     pIServerList = NULL;  
  37.     return 1;  
  38. }  
  39. else if (SUCCEEDED(hr)) {  
  40.     cout << "已连接上需要连接的OPC服务器..." << endl;  
  41. }  
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服务器已连接上。


  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面这段代码是网上抄来的,相信有人也找到过这段,实际上真正运行的时候就会发现其实是有问题的,我把它修改了下,能正常读写了。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; namespace kingview { public partial class Form1 : Form { /// /// 与组态王建立连接 /// 每次应用程序启动时,必须用该函数与组态王建立连接 /// /// node为节点(IP),如果是本机,其值为空 /// 返回错误码,见附录。 [DllImport("kingvewcliend.dll")] public static extern int StartCliend(string node); /// /// 得到组态王SDK中列出的项目(包括变量及其域)总数 /// [DllImport("kingvewcliend.dll")] public static extern int ReadItemNo(); /// /// 得到某个项目的名称 /// 将返回组态王的项目的名称 /// 为用户写入的其要取的变量的索引号,其为ReadItemNo返回的范围内的某个数 /// 返回错误码,见附录 /// [DllImport("kingvewcliend.dll")] //[SecurityPermission(SecurityAction.Assert, Unrestricted = true)] public static extern int GetItemNames(StringBuilder sName, int wItemId); /// /// 将某个项目添加到采集列中 /// 是要加入采集的项目名 /// TagId项目采集的标识号 /// 项目的数据类型 /// 返回错误码,见附录 /// [DllImport("kingvewcliend.dll")] public static extern int AddTag(string sRegName, ref int TagId, ref int TagDataType); /// /// 向某个项目中有应用程序向组态王方向写数据 /// /// 为要采集项目的标识号 /// bVal、lVal、fVal、sVal为设定的数值,用户将根据变量的类型设定数值 /// bVal、lVal、fVal、sVal为设定的数值,用户将根据变量的类型设定数值 /// b

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值