C#开发的OPC客户端代码,比较简单可以实现搜索本地主机,IP以及本地OPC服务器功能,可以添加标签,实现数据的获取及修改。
001 |
using System; |
002 |
using System.Collections.Generic; |
003 |
using System.ComponentModel; |
004 |
using System.Data; |
005 |
using System.Drawing; |
006 |
using System.Linq; |
007 |
using System.Text; |
008 |
using System.Windows.Forms; |
009 |
using System.Net; |
010 |
using OPCAutomation; |
011 |
using System.Net.Sockets; |
012 |
using System.Collections.Specialized; |
013 |
014 |
namespace OMTGate |
015 |
{
|
016 |
public partial class MainForm : Form |
017 |
{
|
018 |
public MainForm() |
019 |
{
|
020 |
InitializeComponent(); |
021 |
} |
022 |
023 |
024 |
#region 私有变量 |
025 |
/// <summary> |
026 |
/// OPCServer Object |
027 |
/// </summary> |
028 |
OPCServer KepServer; |
029 |
/// <summary> |
030 |
/// OPCGroups Object |
031 |
/// </summary> |
032 |
OPCGroups KepGroups; |
033 |
/// <summary> |
034 |
/// OPCGroup Object |
035 |
/// </summary> |
036 |
OPCGroup KepGroup; |
037 |
/// <summary> |
038 |
/// OPCItems Object |
039 |
/// </summary> |
040 |
OPCItems KepItems; |
041 |
/// <summary> |
042 |
/// OPCItem Object |
043 |
/// </summary> |
044 |
OPCItem KepItem; |
045 |
/// <summary> |
046 |
/// 主机IP |
047 |
/// </summary> |
048 |
string strHostIP = "" ; |
049 |
/// <summary> |
050 |
/// 主机名称 |
051 |
/// </summary> |
052 |
string strHostName = "" ; |
053 |
/// <summary> |
054 |
/// 连接状态 |
055 |
/// </summary> |
056 |
bool opc_connected = false ; |
057 |
/// <summary> |
058 |
/// 客户端句柄 |
059 |
/// </summary> |
060 |
int itmHandleClient = 0; |
061 |
/// <summary> |
062 |
/// 服务端句柄 |
063 |
/// </summary> |
064 |
int itmHandleServer = 0; |
065 |
066 |
DataTable dt = new DataTable(); |
067 |
|
068 |
#endregion |
069 |
070 |
private void btnNumeServer_Click( object sender, EventArgs e) |
071 |
{
|
072 |
//获取计算机名 |
073 |
strHostName = Dns.GetHostName(); |
074 |
txtComputerName.Text = strHostName; |
075 |
076 |
//获取IP地址 |
077 |
IPAddress[] localIPs; |
078 |
localIPs = Dns.GetHostAddresses(strHostName); |
079 |
StringCollection IpCollection = new StringCollection(); |
080 |
foreach (IPAddress ip in localIPs) |
081 |
{
|
082 |
//根据AddressFamily判断是否为ipv4,如果是InterNetWorkV6则为ipv6 |
083 |
if (ip.AddressFamily == AddressFamily.InterNetwork) |
084 |
IpCollection.Add(ip.ToString()); |
085 |
} |
086 |
string [] IpArray = new string [IpCollection.Count]; |
087 |
IpCollection.CopyTo(IpArray, 0); |
088 |
foreach ( string ip in IpArray) |
089 |
{
|
090 |
cmbIPAddress.Items.Add(ip); |
091 |
} |
092 |
cmbIPAddress.SelectedIndex = 0; |
093 |
094 |
//获取本地计算机上的OPCServerName |
095 |
try |
096 |
{
|
097 |
KepServer = new OPCServer(); |
098 |
object serverList = KepServer.GetOPCServers(strHostName); |
099 |
100 |
foreach ( string turn in (Array)serverList) |
101 |
{
|
102 |
cmbServerName.Items.Add(turn); |
103 |
} |
104 |
cmbServerName.SelectedIndex = 0; |
105 |
btnConnectServer.Enabled = true ; |
106 |
} |
107 |
catch (Exception err) |
108 |
{
|
109 |
MessageBox.Show( "枚举本地OPC服务器出错:" + err.Message, "提示信息" , MessageBoxButtons.OK, MessageBoxIcon.Warning); |
110 |
} |
111 |
} |
112 |
113 |
private void btnConnectServer_Click( object sender, EventArgs e) |
114 |
{
|
115 |
try |
116 |
{
|
117 |
if (!ConnectRemoteServer(cmbIPAddress.Text, cmbServerName.Text)) |
118 |
{
|
119 |
return ; |
120 |
} |
121 |
122 |
btnSet.Enabled = true ; |
123 |
124 |
opc_connected = true ; |
125 |
126 |
GetServerInfo(); |
127 |
128 |
RecurBrowse(KepServer.CreateBrowser()); |
129 |
130 |
if (!CreateGroup()) |
131 |
{
|
132 |
return ; |
133 |
} |
134 |
} |
135 |
catch (Exception err) |
136 |
{
|
137 |
MessageBox.Show( "初始化出错:" + err.Message, "提示信息" , MessageBoxButtons.OK, MessageBoxIcon.Warning); |
138 |
} |
139 |
} |
140 |
141 |
private void btnSet_Click( object sender, EventArgs e) |
142 |
{
|
143 |
SetGroupProperty(); |
144 |
} |
145 |
146 |
List< string > itemList = new List< string >(); |
147 |
int count = 0; |
148 |
private void btnAddItem_Click( object sender, EventArgs e) |
149 |
{
|
150 |
try |
151 |
{
|
152 |
//if (itmHandleClient != 0) |
153 |
//{
|
154 |
// this.txtTagValue.Text = ""; |
155 |
// this.txtQualities.Text = ""; |
156 |
// this.txtTimeStamps.Text = ""; |
157 |
158 |
// Array Errors; |
159 |
// OPCItem bItem = KepItems.GetOPCItem(itmHandleServer); |
160 |
// //注:OPC中以1为数组的基数 |
161 |
// int[] temp = new int[2] { 0, bItem.ServerHandle }; |
162 |
// Array serverHandle = (Array)temp; |
163 |
// //移除上一次选择的项 |
164 |
// KepItems.Remove(KepItems.Count, ref serverHandle, out Errors); |
165 |
//} |
166 |
itmHandleClient = count; |
167 |
KepItem = KepItems.AddItem(lsbTagList.SelectedItem.ToString(), itmHandleClient); |
168 |
//itemList.Add(lsbTagList.SelectedItem.ToString()); |
169 |
itmHandleServer = KepItem.ServerHandle; |
170 |
count++; |
171 |
textBox1.Text = KepItems.Count.ToString(); |
172 |
DataRow dr = dt.NewRow(); |
173 |
dr[ "标签" ] = lsbTagList.SelectedItem.ToString(); |
174 |
dr[ "测量值" ] = "" ; |
175 |
dr[ "质量" ] = "" ; |
176 |
dr[ "时间戳" ] = "" ; |
177 |
dt.Rows.Add(dr); |
178 |
} |
179 |
catch (Exception err) |
180 |
{
|
181 |
//没有任何权限的项,都是OPC服务器保留的系统项,此处可不做处理。 |
182 |
//itmHandleClient = 0; |
183 |
//txtTagValue.Text = "Error ox"; |
184 |
//txtQualities.Text = "Error ox"; |
185 |
//txtTimeStamps.Text = "Error ox"; |
186 |
MessageBox.Show( "此项为系统保留项:" + err.Message, "提示信息" ); |
187 |
} |
188 |
} |
189 |
190 |
/// <summary> |
191 |
/// 设置组属性 |
192 |
/// </summary> |
193 |
private void SetGroupProperty() |
194 |
{
|
195 |
KepServer.OPCGroups.DefaultGroupIsActive = Convert.ToBoolean(txtGroupIsActive.Text); |
196 |
KepServer.OPCGroups.DefaultGroupDeadband = Convert.ToInt32(txtGroupDeadband.Text); |
197 |
KepGroup.UpdateRate = Convert.ToInt32(txtUpdateRate.Text); |
198 |
KepGroup.IsActive = Convert.ToBoolean(txtIsActive.Text); |
199 |
KepGroup.IsSubscribed = Convert.ToBoolean(txtIsSubscribed.Text); |
200 |
} |
201 |
202 |
/// <summary> |
203 |
/// 连接OPC服务器 |
204 |
/// </summary> |
205 |
/// <param name="remoteServerIP">OPCServerIP</param> |
206 |
/// <param name="remoteServerName">OPCServer名称</param> |
207 |
private bool ConnectRemoteServer( string remoteServerIP, string remoteServerName) |
208 |
{
|
209 |
try |
210 |
{
|
211 |
KepServer.Connect(remoteServerName, remoteServerIP); |
212 |
213 |
if (KepServer.ServerState == ( int )OPCServerState.OPCRunning) |
214 |
{
|
215 |
tsslServerState.Text = "已连接到-" + KepServer.ServerName + " " ; |
216 |
} |
217 |
else |
218 |
{
|
219 |
//这里你可以根据返回的状态来自定义显示信息,请查看自动化接口API文档 |
220 |
tsslServerState.Text = "状态:" + KepServer.ServerState.ToString() + " " ; |
221 |
} |
222 |
} |
223 |
catch (Exception err) |
224 |
{
|
225 |
MessageBox.Show( "连接远程服务器出现错误:" + err.Message, "提示信息" , MessageBoxButtons.OK, MessageBoxIcon.Warning); |
226 |
return false ; |
227 |
} |
228 |
return true ; |
229 |
} |
230 |
231 |
/// <summary> |
232 |
/// 获取服务器信息,并显示在窗体状态栏上 |
233 |
/// </summary> |
234 |
private void GetServerInfo() |
235 |
{
|
236 |
tsslServerStartTime.Text = "开始时间:" + KepServer.StartTime.ToString() + " " ; |
237 |
tsslversion.Text = "版本:" + KepServer.MajorVersion.ToString() + "." + KepServer.MinorVersion.ToString() + "." + KepServer.BuildNumber.ToString(); |
238 |
} |
239 |
240 |
/// <summary> |
241 |
/// 列出OPC服务器中所有节点 |
242 |
/// </summary> |
243 |
/// <param name="oPCBrowser"></param> |
244 |
private void RecurBrowse(OPCBrowser oPCBrowser) |
245 |
{
|
246 |
//展开分支 |
247 |
oPCBrowser.ShowBranches(); |
248 |
//展开叶子 |
249 |
oPCBrowser.ShowLeafs( true ); |
250 |
foreach ( object turn in oPCBrowser) |
251 |
{
|
252 |
lsbTagList.Items.Add(turn.ToString()); |
253 |
} |
254 |
} |
255 |
256 |
/// <summary> |
257 |
/// 创建组 |
258 |
/// </summary> |
259 |
private bool CreateGroup() |
260 |
{
|
261 |
try |
262 |
{
|
263 |
KepGroups = KepServer.OPCGroups; |
264 |
KepGroup = KepGroups.Add( "OPCDOTNETGROUP" ); |
265 |
SetGroupProperty(); |
266 |
KepGroup.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(KepGroup_DataChange); |
267 |
KepGroup.AsyncWriteComplete += new DIOPCGroupEvent_AsyncWriteCompleteEventHandler(KepGroup_AsyncWriteComplete); |
268 |
KepItems = KepGroup.OPCItems; |
269 |
} |
270 |
catch (Exception err) |
271 |
{
|
272 |
MessageBox.Show( "创建组出现错误:" + err.Message, "创建组出错" , MessageBoxButtons.OK, MessageBoxIcon.Warning); |
273 |
return false ; |
274 |
} |
275 |
return true ; |
276 |
} |
277 |
278 |
/// <summary> |
279 |
/// 每当项数据有变化时执行的事件 |
280 |
/// </summary> |
281 |
/// <param name="TransactionID">处理ID</param> |
282 |
/// <param name="NumItems">项个数</param> |
283 |
/// <param name="ClientHandles">项客户端句柄</param> |
284 |
/// <param name="ItemValues">TAG值</param> |
285 |
/// <param name="Qualities">品质</param> |
286 |
/// <param name="TimeStamps">时间戳</param> |
287 |
void KepGroup_DataChange( int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps) |
288 |
{
|
289 |
//DataTable dt = new DataTable(); |
290 |
//dt.Columns.Add("标签", System.Type.GetType("System.String")); |
291 |
//dt.Columns.Add("测量值", System.Type.GetType("System.String")); |
292 |
//dt.Columns.Add("质量", System.Type.GetType("System.String")); |
293 |
//dt.Columns.Add("时间戳", System.Type.GetType("System.String")); |
294 |
|
295 |
//为了测试,所以加了控制台的输出,来查看事物ID号 |
296 |
//Console.WriteLine("********"+TransactionID.ToString()+"*********"); |
297 |
for ( int i = 1; i <= NumItems; i++) |
298 |
{
|
299 |
//DataRow dr = dt.NewRow(); |
300 |
//dr["标签"] = itemList[i-1]; |
301 |
//dt.Columns["测量值"][i] = ItemValues.GetValue(i).ToString(); |
302 |
//dt.Columns["质量"][i] = Qualities.GetValue(i).ToString(); |
303 |
//dt.Columns["时间戳"][i] = TimeStamps.GetValue(i).ToString(); |
304 |
textBox2.Text = ClientHandles.GetValue(i).ToString(); |
305 |
dt.Rows[Convert.ToInt32(ClientHandles.GetValue(i).ToString().Trim())][1] = ItemValues.GetValue(i).ToString(); |
306 |
dt.Rows[Convert.ToInt32(ClientHandles.GetValue(i).ToString().Trim())][2] = Qualities.GetValue(i).ToString(); |
307 |
dt.Rows[Convert.ToInt32(ClientHandles.GetValue(i).ToString().Trim())][3] = TimeStamps.GetValue(i).ToString(); |
308 |
//dt.Rows.Add(dr); |
309 |
} |
310 |
//dgvResultList.DataSource = dt; |
311 |
} |
312 |
313 |
/// <summary> |
314 |
/// 写入TAG值时执行的事件 |
315 |
/// </summary> |
316 |
/// <param name="TransactionID"></param> |
317 |
/// <param name="NumItems"></param> |
318 |
/// <param name="ClientHandles"></param> |
319 |
/// <param name="Errors"></param> |
320 |
void KepGroup_AsyncWriteComplete( int TransactionID, int NumItems, ref Array ClientHandles, ref Array Errors) |
321 |
{
|
322 |
lblState.Text = "" ; |
323 |
for ( int i = 1; i <= NumItems; i++) |
324 |
{
|
325 |
lblState.Text += "Tran:" + TransactionID.ToString() + " CH:" + ClientHandles.GetValue(i).ToString() + " Error:" + Errors.GetValue(i).ToString(); |
326 |
} |
327 |
} |
328 |
329 |
private void MainForm_FormClosing( object sender, FormClosingEventArgs e) |
330 |
{
|
331 |
if (!opc_connected) |
332 |
{
|
333 |
return ; |
334 |
} |
335 |
336 |
if (KepGroup != null ) |
337 |
{
|
338 |
KepGroup.DataChange -= new DIOPCGroupEvent_DataChangeEventHandler(KepGroup_DataChange); |
339 |
} |
340 |
341 |
if (KepServer != null ) |
342 |
{
|
343 |
KepServer.Disconnect(); |
344 |
KepServer = null ; |
345 |
} |
346 |
347 |
opc_connected = false ; |
348 |
} |
349 |
350 |
private void MainForm_Load( object sender, EventArgs e) |
351 |
{
|
352 |
dt.Columns.Add( "标签" , System.Type.GetType( "System.String" )); |
353 |
dt.Columns.Add( "测量值" , System.Type.GetType( "System.String" )); |
354 |
dt.Columns.Add( "质量" , System.Type.GetType( "System.String" )); |
355 |
dt.Columns.Add( "时间戳" , System.Type.GetType( "System.String" )); |
356 |
357 |
dgvResultList.DataSource = dt; |
358 |
} |
359 |
} |
360 |
} |
http://bbs.51cto.com/thread-1065491-1-1.html
标签和数据的显示是设计了一个表格,可以动态添加标签,显示标签名称、实时值、质量及时间戳。用于实际项目尚需修改!