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工程项目文件

  1. 基本类库视图

    下图是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 id
string hostName = string.Empty; //local server
Type 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 name
int 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 包装组件下载:

OpcRcw.zip

源代码下载:

OpcDaClient.zip

(OPC Client .NET 开发类库)网上很多网友都有提过,.NET开发OPC Client不外乎下面三种方法的更多相关文章

  1. 体温数据上传程序开发+获取时间的三种方法+DB Browser下载及安装

    今天开始了体温上传程序的开发 今日所学: 获取时间 (21条消息) (转)安卓获取时间的三种方法_sharpeha的博客-CSDN博客_安卓获取时间 DB Browser安装教程 (20条消息) sq ...

  2. C#中??和?分别是什么意思? 在ASP.NET开发中一些单词的标准缩写 C#SESSION丢失问题的解决办法 在C#中INTERFACE与ABSTRACT CLASS的区别 SQL命令语句小技巧 JQUERY判断CHECKBOX是否选中三种方法 JS中!=、==、!==、===的用法和区别 在对象比较中,对象相等和对象一致分别指的是什么?

    C#中??和?分别是什么意思? 在C#中??和?分别是什么意思? 1. 可空类型修饰符(?):引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空.例如:string str=null; ...

  3. Java Web开发中用Tomcat部署项目的三种方法

    第一种方法:在tomcat中的conf目录中,在server.xml中的,<host/>节点中添加: <Context path="/hello" docBase ...

  4. LwIP协议栈开发嵌入式网络的三种方法分析

    LwIP协议栈开发嵌入式网络的三种方法分析   摘要  轻量级的TCP/IP协议栈LwIP,提供了三种应用程序设计方法,且很容易被移植到多任务的操作系统中.本文结合μC/OS-II这一实时操作系统,以 ...

  5. struts2开发action 的三种方法以及通配符、路径匹配原则、常量

    struts2开发action 的三种方法 1.继承ActionSupport public class UserAction extends ActionSupport { // Action中业务 ...

  6. 痞子衡嵌入式:在IAR开发环境下将关键函数重定向到RAM中执行的三种方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在IAR开发环境下将关键函数重定向到RAM中执行的三种方法. 嵌入式项目里应用程序代码正常是放在 Flash 中执行的,但有时候也需要将 ...

  7. Android开发中完全退出程序的三种方法

    参考: http://android.tgbus.com/Android/tutorial/201108/363511.shtml Android程序有很多Activity,比如说主窗口A,调用了子窗 ...

  8. 安卓开发笔记(十八):实现button按钮事件的三种方法

    Android开发中有三种主要的方式用于设置View的点击事件,1.创建内部类:2.主类中实现OnClickListener接口:3.使用匿名内部类.这三种方式都用到了OnClickListener接 ...

  9. Servlet开发的三种方法

    第一种 实现 Servlet 接口,需要覆写 Servlet 的5个方法,并将ServletConfig对象保存到类级变量中 package app01a; import java.io.IOExce ...

随机推荐

  1. 006PHP基础知识——数据类型(三)

    <?php /** * 数据类型(三) * PHP是一个弱类型的语言 */ //检测数据类型:gettype() 返回字符串的数据类型 /*$str="美丽中国"; echo ...

  2. 重温MVC基础入门

    重温MVC基础入门   简介 本文主要是作者回顾MVC基础的文章,整合个人认为基础且重点的信息,通过简单实践进行复习. 相关代码地址:https://github.com/OtherRuan/Revi ...

  3. hdu2732

    题解: 和上一题差不多 然后注意格式 代码: #include<cstdio> #include<cmath> #include<algorithm> #inclu ...

  4. bzoj3000

    题解: n!k进制的位数 首先考虑n!十进制的位数 =log10(n!) 然后用阶乘近似公式 继而换底 得到答案 代码: #include<bits/stdc++.h> using nam ...

  5. JBPM4入门——1.jbpm简要介绍

    本博文只是简要对JBPM4进行介绍,如需更详细内容请自行google 链接: JBPM入门系列文章: JBPM4入门——1.jbpm简要介绍 JBPM4入门——2.在eclipse中安装绘制jbpm流 ...

  6. php 请求url获取状态码

    function get_http_code($url) { $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); //设置URL c ...

  7. iOS Xcode全面剖析

    链接:http://www.jianshu.com/p/3c8527898e84 一.创建新一个工程二.Xcode界面详细介绍三.Xcode菜单详解四.Xcode快捷键介绍五.结语六.参考资料 前言 ...

  8. SCRF的简介及防护手段

    CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造. CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求. 包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购 ...

  9. 网络请求工具 cURL

    网络请求工具 cURL 2017-08-16 cRUL 是一种命令行工具,作用是发出网络请求,然后得到和提取数据,显示在“标准输出”(stdout)上面. 查看网页源码 1 $ curl baidu. ...

  10. 在线机器学习FTRL(Follow-the-regularized-Leader)算法介绍

    看到好文章,坚决转载!哈哈,学术目的~~ 最近几个同事在做推荐平台的项目,都问到怎么实现FTRL算法,要求协助帮忙实现FTRL的算法模块.今天也是有空,赶紧来做个整理.明天还要去上海参加天善智能组织的 ...