(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 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不外乎下面三种方法...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 面试之Java知识整理
- 下一篇: 优达学城数据分析师纳米学位——P3项目知