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

  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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM