http://www.cnblogs.com/badnewfish/archive/2009/04/11/1374966.htmlhtml
本例下載/Files/badnewfish/OPC測試經過.rar程序員
前幾天我就發佈過這篇文章,惋惜的是,發佈後代碼有的卻看不到,後來我就刪了,至今不明白什麼緣由- -!服務器
關於C++、VB來開發OPC客戶端的資料網上有不少,但C#的至今沒發現有多少。網絡
因爲近期項目的須要,就開發了OPC客戶端的一個模塊。在我想來,程序員挺累的,緣由我很累。因此我想你們也很累~~~嘿嘿。工具
特別是剛接手OPC客戶端開發的前幾天,每天盯住顯示器,百度、GOOGLE不停的搜索。天天早上醒來,眼睛都瑟瑟的。開發工具
從事3年以上軟件開發的朋友們,估計都會腰痠背痛吧!反正我是這樣的。測試
不說那麼多廢話了,貼上源碼,讓須要的同行看看吧,代碼的質量並不高,就當作拋磚引玉吧!
一、枚舉本地服務器
二、獲取服務器信息
三、列出了服務器上Tag
四、能夠設置組的屬性
五、讀\寫功能
六、可進行遠程鏈接(DCOM需配置)
先看圖:
引用類庫:
OPC服務器:
開發工具:
當前環境:
源碼:
1 Code 2 3 ///摘要 4 5 ///程式使用C#.NET 2005 編寫 6 7 ///引用類庫OPCDAAuto.dll 8 9 ///OPCServer採用KEPWare 10 11 ///在windows xp sp二、sp三、windows 2003上測試經過 12 13 ///完成於:2008年12月31日 14 15 ///測試於:2009年01月05日 16 17 /// 18 19 ///做者:瀟灑草 20 21 ///Email:zhkai868@163.com 22 23 ///QQ:44649029 24 25 /// 26 27 ///如分發,請保留此摘要。 28 29 ///鄙視那些拿代碼當寶貝的人,鄙視那些你不拿源碼換就不稀罕你的人,鄙視那些自私的人。 30 31 ///別人看到你的代碼,你能死啊?對你有多大威脅啊?強烈鄙視~~~ 32 33 ///若是你是這樣的人,趕忙關了。。偶不歡迎。。 34 35 using System; 36 37 using System.Collections.Generic; 38 39 using System.ComponentModel; 40 41 using System.Data; 42 43 using System.Drawing; 44 45 using System.Text; 46 47 using System.Windows.Forms; 48 49 using System.Net; 50 51 using System.Collections; 52 53 using OPCAutomation; 54 55 56 57 namespace OPC測試經過 58 59 { 60 61 public partial class MainFrom : Form 62 63 { 64 65 public MainFrom() 66 67 { 68 69 InitializeComponent(); 70 71 } 72 73 74 75 #region 私有變量 76 77 /// <summary> 78 79 /// OPCServer Object 80 81 /// </summary> 82 83 OPCServer KepServer; 84 85 /// <summary> 86 87 /// OPCGroups Object 88 89 /// </summary> 90 91 OPCGroups KepGroups; 92 93 /// <summary> 94 95 /// OPCGroup Object 96 97 /// </summary> 98 99 OPCGroup KepGroup; 100 101 /// <summary> 102 103 /// OPCItems Object 104 105 /// </summary> 106 107 OPCItems KepItems; 108 109 /// <summary> 110 111 /// OPCItem Object 112 113 /// </summary> 114 115 OPCItem KepItem; 116 117 /// <summary> 118 119 /// 主機IP 120 121 /// </summary> 122 123 string strHostIP = ""; 124 125 /// <summary> 126 127 /// 主機名稱 128 129 /// </summary> 130 131 string strHostName = ""; 132 133 /// <summary> 134 135 /// 鏈接狀態 136 137 /// </summary> 138 139 bool opc_connected = false; 140 141 /// <summary> 142 143 /// 客戶端句柄 144 145 /// </summary> 146 147 int itmHandleClient = 0; 148 149 /// <summary> 150 151 /// 服務端句柄 152 153 /// </summary> 154 155 int itmHandleServer = 0; 156 157 #endregion 158 159 160 161 #region 方法 162 163 /// <summary> 164 165 /// 枚舉本地OPC服務器 166 167 /// </summary> 168 169 private void GetLocalServer() 170 171 { 172 173 //獲取本地計算機IP,計算機名稱 174 175 IPHostEntry IPHost = Dns.Resolve(Environment.MachineName); 176 177 if (IPHost.AddressList.Length > 0) 178 179 { 180 181 strHostIP = IPHost.AddressList[0].ToString(); 182 183 } 184 185 else 186 187 { 188 189 return; 190 191 } 192 193 //經過IP來獲取計算機名稱,可用在局域網內 194 195 IPHostEntry ipHostEntry = Dns.GetHostByAddress(strHostIP); 196 197 strHostName=ipHostEntry.HostName.ToString(); 198 199 200 201 //獲取本地計算機上的OPCServerName 202 203 try 204 205 { 206 207 KepServer = new OPCServer(); 208 209 object serverList = KepServer.GetOPCServers(strHostName); 210 211 212 213 foreach (string turn in (Array)serverList) 214 215 { 216 217 cmbServerName.Items.Add(turn); 218 219 } 220 221 222 223 cmbServerName.SelectedIndex = 0; 224 225 btnConnServer.Enabled = true; 226 227 } 228 229 catch(Exception err) 230 231 { 232 233 MessageBox.Show("枚舉本地OPC服務器出錯:"+err.Message,"提示信息",MessageBoxButtons.OK,MessageBoxIcon.Warning); 234 235 } 236 237 238 239 } 240 241 /// <summary> 242 243 /// 建立組 244 245 /// </summary> 246 247 private bool CreateGroup() 248 249 { 250 251 try 252 253 { 254 255 KepGroups = KepServer.OPCGroups; 256 257 KepGroup = KepGroups.Add("OPCDOTNETGROUP"); 258 259 SetGroupProperty(); 260 261 KepGroup.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(KepGroup_DataChange); 262 263 KepGroup.AsyncWriteComplete += new DIOPCGroupEvent_AsyncWriteCompleteEventHandler(KepGroup_AsyncWriteComplete); 264 265 KepItems = KepGroup.OPCItems; 266 267 } 268 269 catch (Exception err) 270 271 { 272 273 MessageBox.Show("建立組出現錯誤:"+err.Message,"提示信息",MessageBoxButtons.OK,MessageBoxIcon.Warning); 274 275 return false; 276 277 } 278 279 return true; 280 281 } 282 283 /// <summary> 284 285 /// 設置組屬性 286 287 /// </summary> 288 289 private void SetGroupProperty() 290 291 { 292 293 KepServer.OPCGroups.DefaultGroupIsActive =Convert.ToBoolean(txtGroupIsActive.Text); 294 295 KepServer.OPCGroups.DefaultGroupDeadband = Convert.ToInt32(txtGroupDeadband.Text); 296 297 KepGroup.UpdateRate = Convert.ToInt32(txtUpdateRate.Text); 298 299 KepGroup.IsActive = Convert.ToBoolean(txtIsActive.Text); 300 301 KepGroup.IsSubscribed =Convert.ToBoolean(txtIsSubscribed.Text); 302 303 } 304 305 /// <summary> 306 307 /// 列出OPC服務器中全部節點 308 309 /// </summary> 310 311 /// <param name="oPCBrowser"></param> 312 313 private void RecurBrowse(OPCBrowser oPCBrowser) 314 315 { 316 317 //展開分支 318 319 oPCBrowser.ShowBranches(); 320 321 //展開葉子 322 323 oPCBrowser.ShowLeafs(true); 324 325 foreach (object turn in oPCBrowser) 326 327 { 328 329 listBox1.Items.Add(turn.ToString()); 330 331 } 332 333 } 334 335 /// <summary> 336 337 /// 獲取服務器信息,並顯示在窗體狀態欄上 338 339 /// </summary> 340 341 private void GetServerInfo() 342 343 { 344 345 tsslServerStartTime.Text ="開始時間:"+ KepServer.StartTime.ToString()+" "; 346 347 tsslversion.Text ="版本:"+ KepServer.MajorVersion.ToString() + "." + KepServer.MinorVersion.ToString()+"."+KepServer.BuildNumber.ToString(); 348 349 } 350 351 /// <summary> 352 353 /// 鏈接OPC服務器 354 355 /// </summary> 356 357 /// <param name="remoteServerIP">OPCServerIP</param> 358 359 /// <param name="remoteServerName">OPCServer名稱</param> 360 361 private bool ConnectRemoteServer(string remoteServerIP, string remoteServerName) 362 363 { 364 365 try 366 367 { 368 369 KepServer.Connect(remoteServerName, remoteServerIP); 370 371 372 373 if (KepServer.ServerState == (int)OPCServerState.OPCRunning) 374 375 { 376 377 tsslServerState.Text = "已鏈接到-" + KepServer.ServerName + " "; 378 379 } 380 381 else 382 383 { 384 385 //這裏你能夠根據返回的狀態來自定義顯示信息,請查看自動化接口API文檔 386 387 tsslServerState.Text = "狀態:" + KepServer.ServerState.ToString() + " "; 388 389 } 390 391 } 392 393 catch (Exception err) 394 395 { 396 397 MessageBox.Show("鏈接遠程服務器出現錯誤:" + err.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning); 398 399 return false; 400 401 } 402 403 return true; 404 405 } 406 407 #endregion 408 409 410 411 #region 事件 412 413 /// <summary> 414 415 /// 寫入TAG值時執行的事件 416 417 /// </summary> 418 419 /// <param name="TransactionID"></param> 420 421 /// <param name="NumItems"></param> 422 423 /// <param name="ClientHandles"></param> 424 425 /// <param name="Errors"></param> 426 427 void KepGroup_AsyncWriteComplete(int TransactionID, int NumItems, ref Array ClientHandles, ref Array Errors) 428 429 { 430 431 lblState.Text = ""; 432 433 for (int i = 1; i <= NumItems; i++) 434 435 { 436 437 lblState.Text += "Tran:" + TransactionID.ToString() + " CH:" + ClientHandles.GetValue(i).ToString() + " Error:" + Errors.GetValue(i).ToString(); 438 439 } 440 441 } 442 443 /// <summary> 444 445 /// 每當項數據有變化時執行的事件 446 447 /// </summary> 448 449 /// <param name="TransactionID">處理ID</param> 450 451 /// <param name="NumItems">項個數</param> 452 453 /// <param name="ClientHandles">項客戶端句柄</param> 454 455 /// <param name="ItemValues">TAG值</param> 456 457 /// <param name="Qualities">品質</param> 458 459 /// <param name="TimeStamps">時間戳</param> 460 461 void KepGroup_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps) 462 463 { 464 465 //爲了測試,因此加了控制檯的輸出,來查看事物ID號 466 467 //Console.WriteLine("********"+TransactionID.ToString()+"*********"); 468 469 for (int i = 1; i <= NumItems; i++) 470 471 { 472 473 this.txtTagValue.Text = ItemValues.GetValue(i).ToString(); 474 475 this.txtQualities.Text = Qualities.GetValue(i).ToString(); 476 477 this.txtTimeStamps.Text = TimeStamps.GetValue(i).ToString(); 478 479 } 480 481 } 482 483 /// <summary> 484 485 /// 選擇列表項時處理的事情 486 487 /// </summary> 488 489 /// <param name="sender"></param> 490 491 /// <param name="e"></param> 492 493 private void listBox1_SelectedIndexChanged(object sender, EventArgs e) 494 495 { 496 497 try 498 499 { 500 501 if (itmHandleClient != 0) 502 503 { 504 505 this.txtTagValue.Text = ""; 506 507 this.txtQualities.Text =""; 508 509 this.txtTimeStamps.Text = ""; 510 511 512 513 Array Errors; 514 515 OPCItem bItem = KepItems.GetOPCItem(itmHandleServer); 516 517 //注:OPC中以1爲數組的基數 518 519 int[] temp = new int[2] { 0, bItem.ServerHandle }; 520 521 Array serverHandle = (Array)temp; 522 523 //移除上一次選擇的項 524 525 KepItems.Remove(KepItems.Count, ref serverHandle, out Errors); 526 527 } 528 529 itmHandleClient = 1234; 530 531 KepItem = KepItems.AddItem(listBox1.SelectedItem.ToString(), itmHandleClient); 532 533 itmHandleServer = KepItem.ServerHandle; 534 535 } 536 537 catch(Exception err) 538 539 { 540 541 //沒有任何權限的項,都是OPC服務器保留的系統項,此處可不作處理。 542 543 itmHandleClient = 0; 544 545 txtTagValue.Text = "Error ox"; 546 547 txtQualities.Text = "Error ox"; 548 549 txtTimeStamps.Text = "Error ox"; 550 551 MessageBox.Show("此項爲系統保留項:"+err.Message,"提示信息"); 552 553 } 554 555 } 556 557 /// <summary> 558 559 /// 載入窗體時處理的事情 560 561 /// </summary> 562 563 private void MainFrom_Load(object sender, EventArgs e) 564 565 { 566 567 GetLocalServer(); 568 569 } 570 571 /// <summary> 572 573 /// 關閉窗體時處理的事情 574 575 /// </summary> 576 577 private void MainFrom_FormClosing(object sender, FormClosingEventArgs e) 578 579 { 580 581 if (!opc_connected) 582 583 { 584 585 return; 586 587 } 588 589 590 591 if (KepGroup != null) 592 593 { 594 595 KepGroup.DataChange -= new DIOPCGroupEvent_DataChangeEventHandler(KepGroup_DataChange); 596 597 } 598 599 600 601 if (KepServer != null) 602 603 { 604 605 KepServer.Disconnect(); 606 607 KepServer = null; 608 609 } 610 611 612 613 opc_connected = false; 614 615 } 616 617 /// <summary> 618 619 /// 【按鈕】設置 620 621 /// </summary> 622 623 private void btnSetGroupPro_Click(object sender, EventArgs e) 624 625 { 626 627 SetGroupProperty(); 628 629 } 630 631 /// <summary> 632 633 /// 【按鈕】鏈接OPC服務器 634 635 /// </summary> 636 637 private void btnConnLocalServer_Click(object sender, EventArgs e) 638 639 { 640 641 try 642 643 { 644 645 if (!ConnectRemoteServer(txtRemoteServerIP.Text,cmbServerName.Text)) 646 647 { 648 649 return; 650 651 } 652 653 654 655 btnSetGroupPro.Enabled = true; 656 657 658 659 opc_connected = true; 660 661 662 663 GetServerInfo(); 664 665 666 667 RecurBrowse(KepServer.CreateBrowser()); 668 669 670 671 if (!CreateGroup()) 672 673 { 674 675 return; 676 677 } 678 679 } 680 681 catch (Exception err) 682 683 { 684 685 MessageBox.Show("初始化出錯:" + err.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning); 686 687 } 688 689 } 690 691 /// <summary> 692 693 /// 【按鈕】寫入 694 695 /// </summary> 696 697 private void btnWrite_Click(object sender, EventArgs e) 698 699 { 700 701 OPCItem bItem = KepItems.GetOPCItem(itmHandleServer); 702 703 int[] temp = new int[2] { 0, bItem.ServerHandle }; 704 705 Array serverHandles=(Array)temp; 706 707 object[] valueTemp = new object[2] {"",txtWriteTagValue.Text }; 708 709 Array values=(Array)valueTemp; 710 711 Array Errors; 712 713 int cancelID; 714 715 KepGroup.AsyncWrite(1,ref serverHandles,ref values,out Errors, 2009,out cancelID); 716 717 //KepItem.Write(txtWriteTagValue.Text);//這句也能夠寫入,但並不觸發寫入事件 718 719 GC.Collect(); 720 721 } 722 723 #endregion 724 725 } 726 727 }
自動化接口API文檔:
關於DCOM的配置:
update:
一、本文中是在2009年元月寫的,可能有不少過期之處,如今最新(2014年)的OPC官網已經有關於C#調用的例子:http://www.opcfoundation.org/default.aspx/classicdownloads.asp?MID=Developers
二、客戶端鏈接OPC服務器注意事項:
a、本例採用的OPCDAAuto.dll版本是2.2.5.20。 b、須要使用「regsvr32 /s OPCDAAuto.dll」命令在客戶端計算機上註冊這個程序集。 c、首先保證客戶機和服務器的網絡是聯通的。