(OPC Client .NET 开发类库)网上很多网友都有提过,.NET开发OPC Client不外乎下面三种方法
1. 背景
OPC Data Access 规范是基于COM/DCOM定义的,因此大多数的OPC DA Server和client都是基于C++开发的,因为C++对COM/DCOM有最好的支持。现在,随着微软的开发平台渐渐的转移到.NET框架上,好多OPC Client程序都需要建立在.NET平台上,用.NET提供的技术开发OPC Client就成为一种需求。网上很多网友都有提过,.NET开发OPC Client不外乎下面三种方法:
- 使用OPCNetAPI 2.0,需要用到OPCNetAPI.dll,OPCNetAPI.Com.dll;
- 使用自动化接口,需要用到OPCDAAuto.dll;
- 使用自定义接口,需要用到多个.NET Wrapper:OpcRcw.Ae.dll,OpcRcw.Batch.dll,OpcRcw.Comn.dll,OpcRcw.Da.dll,OpcRcw.Dx.dll,OpcRcw.Hda.dll,OpcRcw.Sec.dll;
OPCNetAPI 2.0由OPC foundation提供,只有注册会员才能得到,是需要付费的。其他的dll不需要付费,很容易得到。网上有网友已经介绍过使用OPCDAAuto.dll开发.NET Client的方法, 这种方法的优点是比较简单,缺点是不够灵活。本文使用自定义接口,借助OpcRcw.Da.dll,开发出一个OPC .NET Client的类库,可供其他client程序调用。
必要文件:
OpcRcw.Comn.dll --- 包含对IConnectionPointContainer的包装。
OpcRcw.Da.dll ---.NET 对OPC COM 接口 定义的包装。
适应版本:
OPC Data Access specification 2.05
说明:
该类库正在开发中,这是第一个版本,只实现了一些基本功能,好多功能如OPC Browse等还未实现,代码也未经过测试,存在bug在所难免,感兴趣的朋友请继续关注。。。
2. VS2008工程项目文件

- 基本类库视图
下图是OpcDa.Client组件实现的基本类库:


3. 类库实现的基本功能
OpcServer:
|
Connect |
连接OPC Server。 |
|
Disconnect |
断开Server。 |
|
GetStatus |
获得Server的当前状态,返回ServerStatus。 |
|
AddGroup |
添加group |
|
RemoveGroup |
删除group |
|
FindGroupByName |
通过名字获取OpcGroup对象 |
Opc Group:
|
AddItems |
添加Opc Items到组 |
|
RemoveItems |
删除items |
|
AsyncRead |
异步读取Items,调用IOPCAsyncIO2::Read接口 |
|
AsyncWrite |
异步写items,调用IOPCAsyncIO2::Write接口 |
|
Refresh |
刷新当前group,调用IOPCAsyncIO2::Refresh接口 |
|
GetState |
获得当前group状态,返回GroupState |
|
SetState |
设置当前group状态,返回设置后的group状态 |
|
DataChanged |
事件,客户端注册,可用来接收OnDataChange事件 |
4. 类库使用方法
1) 连接OPC DA server
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
string serverProgID = "OPCSample.OpcDa20Server.1"; // opc da sample server prog idstring hostName = string.Empty; //local serverType tp = Type.GetTypeFromProgID(serverProgID);this._opcServer = new OpcServer(tp.GUID.ToString(), hostName);try{ this._opcServer.Connect();}catch (Exception ex){ MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);} |
2) 断开OPC Server
|
1
2
3
4
5
|
if (this._opcServer != null) { this._opcServer.Disconnect(); this._opcServer = null; } |
3) 添加Group
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
string groupName = "grp_0"; // group nameint updateRate = 1000;bool active = true;try{ OpcGroup grp = this._opcServer.AddGroup(groupName, updateRate, active); grp.DataChanged += OnDataChange; //register OnDataChange Event}catch (Exception ex){ MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);} |
其中OnDataChange 定义为DataChangedEventHandler类型:
|
1
2
3
|
public delegate void DataChangedEventHandler(object subscriptionHandle, object requestHandle, ItemValueResult[] values); private void OnDataChange(object subscriptionHandle, object requestHandle, ItemValueResult[] values); |
4) 删除Group
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
try{ OpcGroup grp = this._opcServer.FindGroupByName(groupName ); if (grp != null) { grp.DataChanged -= OnDataChange; //unregister OnDataChange Event this._opcServer.RemoveGroup(grp); }}catch (Exception ex){ MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);} |
5) 添加Items
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
List<string> items = new List<string>();Items.Add("itemname");OpcGroup grp = this._opcServer.FindGroupByName(groupName);if (grp != null){ try { ItemResult[] results = grp.AddItems(items.ToArray()); foreach (ItemResult result in results) { if (result.ResultID.Failed()) { string message = "Failed to add item \'" + result.ItemName + "\'" + " Error: " + result.ResultID.Name; MessageBox.Show(message); } else { AddItemToList(result); // add item to view list } } } // end try catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } // end catch} // end if |
6) 删除Items
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
// remove items// List<object> itemsClientHandle = new List<object>(); //if (itemsClientHandle.Count > 0){ try { // get group OpcGroup grp = this._opcServer.FindGroupByName(groupName); if (grp != null) { IdentifiedResult[] results = grp.RemoveItems(itemsClientHandle.ToArray()); for (int i = 0; i < results.Length; i++) { if (results[i].ResultID.Succeeded()) { // remove opc item from server successfully, remove it from list RemoveItemFromList(results[i]); } else { string message = "Remove item \'" + results[i].ItemName + "\' error: " + results[i].ResultID.ToString(); MessageBox.Show(message); } } } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } // end catch} |
7) 异步读取Items
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
List<object> clientHandles = new List<object>();foreach (ListViewItem lvItem in items){ ItemResult item = (ItemResult)lvItem.Tag; if (item != null) { clientHandles.Add(item.ClientHandle); }}if (clientHandles.Count > 0){ // get group OpcGroup grp = this._opcServer.FindGroupByName(groupName); if (grp != null) { try { IdentifiedResult[] results = grp.AsyncRead(clientHandles.ToArray(), ++this._handle, new ReadCompleteEventHandler(OnReadComplete), out this._request); for (int i = 0; i < results.Length; i++) { if (results[i].ResultID.Failed()) { string message = "Failed to read item \'" + results[i].ItemName + "\' error: " + results[i].ResultID.ToString(); MessageBox.Show(message); } } } catch (Exception ex) { MessageBox.Show(ex.Message); } }} |
其中OnReadComplete用来接收异步读取的数据结果,其定义为:
|
1
|
private void OnReadComplete(object clientHandle, ItemValueResult[] values); |
8) 异步写Items
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// get group OpcGroup grp = this._opcServer.FindGroupByName(groupName); if (grp != null) { try { IdentifiedResult[] results = grp.AsyncWrite(new ItemValue[] { itemValue }, ++_handle, new WriteCompleteEventHandler(this.OnWriteComplete), out _request); for (int i = 0; i < results.Length; i++) { if (results[i].ResultID.Failed()) { string message = "Failed to write item \'" + results[i].ItemName + "\' error: " + results[i].ResultID.ToString(); MessageBox.Show(message); } } } catch (Exception ex) { MessageBox.Show(ex.Message); } } |
其中OnWriteComplete用来接收异步写的返回结果,其定义为:
private void OnWriteComplete(object clientHandle, IdentifiedResult[] results);
类库的具体使用举例可以参照OpcTestClient程序。
5. OpcTestClient 用户界面

OPC 接口 .NET 包装组件下载:
源代码下载:
(OPC Client .NET 开发类库)网上很多网友都有提过,.NET开发OPC Client不外乎下面三种方法的更多相关文章
- 体温数据上传程序开发+获取时间的三种方法+DB Browser下载及安装
今天开始了体温上传程序的开发 今日所学: 获取时间 (21条消息) (转)安卓获取时间的三种方法_sharpeha的博客-CSDN博客_安卓获取时间 DB Browser安装教程 (20条消息) sq ...
- C#中??和?分别是什么意思? 在ASP.NET开发中一些单词的标准缩写 C#SESSION丢失问题的解决办法 在C#中INTERFACE与ABSTRACT CLASS的区别 SQL命令语句小技巧 JQUERY判断CHECKBOX是否选中三种方法 JS中!=、==、!==、===的用法和区别 在对象比较中,对象相等和对象一致分别指的是什么?
C#中??和?分别是什么意思? 在C#中??和?分别是什么意思? 1. 可空类型修饰符(?):引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空.例如:string str=null; ...
- Java Web开发中用Tomcat部署项目的三种方法
第一种方法:在tomcat中的conf目录中,在server.xml中的,<host/>节点中添加: <Context path="/hello" docBase ...
- LwIP协议栈开发嵌入式网络的三种方法分析
LwIP协议栈开发嵌入式网络的三种方法分析 摘要 轻量级的TCP/IP协议栈LwIP,提供了三种应用程序设计方法,且很容易被移植到多任务的操作系统中.本文结合μC/OS-II这一实时操作系统,以 ...
- struts2开发action 的三种方法以及通配符、路径匹配原则、常量
struts2开发action 的三种方法 1.继承ActionSupport public class UserAction extends ActionSupport { // Action中业务 ...
- 痞子衡嵌入式:在IAR开发环境下将关键函数重定向到RAM中执行的三种方法
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在IAR开发环境下将关键函数重定向到RAM中执行的三种方法. 嵌入式项目里应用程序代码正常是放在 Flash 中执行的,但有时候也需要将 ...
- Android开发中完全退出程序的三种方法
参考: http://android.tgbus.com/Android/tutorial/201108/363511.shtml Android程序有很多Activity,比如说主窗口A,调用了子窗 ...
- 安卓开发笔记(十八):实现button按钮事件的三种方法
Android开发中有三种主要的方式用于设置View的点击事件,1.创建内部类:2.主类中实现OnClickListener接口:3.使用匿名内部类.这三种方式都用到了OnClickListener接 ...
- Servlet开发的三种方法
第一种 实现 Servlet 接口,需要覆写 Servlet 的5个方法,并将ServletConfig对象保存到类级变量中 package app01a; import java.io.IOExce ...
随机推荐
- linux 普通synflood攻击防范网络参数设置
linux如何防SYN攻击 [root@web ~]# netstat -anp |awk '{print $6}'|sort|uniq -c |sort -rn 172 ESTABLISHED 59 ...
- ansible入门一(Ansible介绍及安装部署)
本节内容: 运维工具 Ansible特性 Ansible架构图和核心组件 安装Ansible 演示使用示例 一.运维工具 作为一个Linux运维人员,需要了解大量的运维工具,并熟知这些工具的差异,能够 ...
- Markdown_04_折叠语法
目录 一.折叠语法 参考资料 一.折叠语法 主要使用的是 html5的 details标签 (1)示例如下: <details> <summary>折叠文本</summa ...
- python3 堆排序
思路: 1.建立堆 2.得到堆顶元素,为最大元素 3.去掉堆顶,将堆最后一个元素放到堆顶,此时可通过一次调整重新使堆有序. 4.堆顶元素为第二大元素. 5.重复步骤3,直到堆变空. 动画 代码: de ...
- js 时差转换 getTimezoneOffset()
如果我们的应用是针对世界各地的,当要把后台(服务器)存的时间展示给不同地区的用户时,这个时间应该经过时差转换. 转成用户客户端本地的时间,然后呈现给用户,即下面用到的getTimezoneOffset ...
- SpringInAction--自动化装配Bean(隐式装配)
关于Bean的介绍就具体不多介绍了,,, Spring在配置时候有三种方案可选 1.在xml中进行显示配置 2.在java中进行显示配置 3.隐式的Bean发现机制和自动装配 今天学习的就是自动化装配 ...
- 左边的div导航根据右部div内容的高自动调整
div结构如下: <div class="mainbody"> <div class="left">导航</div> < ...
- 文件处理工具 gif合成工具 文件后缀批量添加工具 文件夹搜索工具 重复文件查找工具 网页图片解析下载工具等
以下都是一些简单的免费分享的工具,技术支持群:592132877,提供定制化服务开发. Gif动图合成工具 主要功能是扫描指定的文件夹里的所有zip文件,然后提取Zip文件中的图片,并合成一张gif图 ...
- Objective-C-----协议protocol,代码块block,分类category
概述 ObjC的语法主要基于smalltalk进行设计的,除了提供常规的面向对象特性外,还增加了很多其他特性,本文将重点介绍objective-C中一些常用的语法特性. 当然这些内容虽然和其他高级语言 ...
- xshell配置密码公钥登录
1:生成公钥 2:密钥类型选择为rsa,长度为2048,并点击下一步,如下所示: 这里的密码是给密钥设置了密码,那么在使用这个密钥时也要输入密码,也可以设置为空 3:保存密钥 (1):当你选择了输入密 ...