Click here to Skip to main content
15,886,570 members
Articles / Programming Languages / Visual Basic

OPC and .NET with COM Interoperability

Rate me:
Please Sign up or sign in to vote.
4.87/5 (53 votes)
8 Jul 20014 min read 703.8K   17.4K   150  
How to access OPC (OLE for Process Control) from .NET with advanced COM interop
using System;
using System.Threading;
using System.Text;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Diagnostics;
using System.Runtime.InteropServices;

using OPC.Common;
using OPC.Data.Interface;
using OPC.Data;

namespace DirectOPCClient
{
	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class MainForm : System.Windows.Forms.Form
	{
		private System.ComponentModel.IContainer components;

		private System.Windows.Forms.TextBox txtServer;
		private System.Windows.Forms.TextBox txtServerInfo;
		private System.Windows.Forms.TreeView treeOpcItems;
		private System.Windows.Forms.ListView listOpcView;
		private System.Windows.Forms.TextBox txtItemID;
		private System.Windows.Forms.TextBox txtItemQual;
		private System.Windows.Forms.TextBox txtItemTimeSt;
		private System.Windows.Forms.TextBox txtItemValue;
		private System.Windows.Forms.TextBox txtItemDataType;
		private System.Windows.Forms.TextBox txtItemSendValue;
		private System.Windows.Forms.Label label1;
		private System.Windows.Forms.Label label2;
		private System.Windows.Forms.Label label3;
		private System.Windows.Forms.Label label4;
		private System.Windows.Forms.ColumnHeader hdrListCol1;
		private System.Windows.Forms.ColumnHeader hdrListCol2;
		private System.Windows.Forms.Button btnItemWrite;		// workaround to show SelServer Form on applic. start
		private System.Windows.Forms.StatusBar statusBarMain;
		private System.Windows.Forms.StatusBarPanel sbpTimeStart;
		private System.Windows.Forms.StatusBarPanel sbpStatus;
		private System.Windows.Forms.StatusBarPanel sbpDummy;				// node in TreeView
		private System.Windows.Forms.ImageList opctreeicons;
		private System.Windows.Forms.ImageList opclisticons;
		private System.Windows.Forms.TextBox txtItemWriteRes;
		private System.Windows.Forms.Button btnItemMore;
		private System.Windows.Forms.Button btnAbout;


		public Process			thisprocess;			// running OS process

		public string			selectedOpcSrv;			// Name (ProgID) of selected OPC-server
		public OpcServer		theSrv = null;			// root OPCDA object
		public OpcGroup			theGrp = null;			// the only one OPC-Group in this example

		public string			itmFullID;					// fully qualified OPC namespace path
		public int				itmHandleClient;			// 0 if no current item selected
		public int				itmHandleServer;
		public OPCACCESSRIGHTS	itmAccessRights;
		public TypeCode			itmTypeCode;				// saved data type of current item
	
		public bool				first_activated = false;	// workaround to show SelServer Form on applic. start
		public bool				opc_connected = false;		// flag if connected

		public string			rootname = "Root";			// string of TreeView root (dummy)
		public string			selectednode;
		public string			selecteditem;				// item in ListView


		public MainForm()
			{
			thisprocess = Process.GetCurrentProcess();		// see DoConnect for client-name
			InitializeComponent();

			treeOpcItems.PathSeparator = "\t";				// warning: assuming OPC not using tabulator as separator
			}

	protected void theSrv_ServerShutDown( object sender, ShutdownRequestEventArgs e )
		{					// event: the OPC server shuts down
		MessageBox.Show( this, "OPC server shuts down because:" + e.shutdownReason, "ServerShutDown", MessageBoxButtons.OK, MessageBoxIcon.Warning );
		}

	public bool DoInit()
		{
		try
			{
			SelServer	frmSelSrv = new SelServer( );		// create form and let user select a name
			frmSelSrv.ShowDialog( this );
			if( frmSelSrv.selectedOpcSrv == null )
				this.Close();

			selectedOpcSrv = frmSelSrv.selectedOpcSrv;			// OPC server ProgID
			txtServer.Text = selectedOpcSrv;


			// ---------------
			theSrv = new OpcServer();
			if( ! DoConnect( selectedOpcSrv ) )
				return false;

			// add event handler for server shutdown
			theSrv.ShutdownRequested += new ShutdownRequestEventHandler( this.theSrv_ServerShutDown );

			// precreate the only OPC group in this example
			if( ! CreateGroup() )
				return false;

			// browse the namespace of the OPC-server
			if( ! DoBrowse() )
				return false;
			}
		catch( Exception e )		// exceptions MUST be handled
			{
			MessageBox.Show( this, "init error! " + e.ToString(), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Warning );
			return false;
			}
		return true;
		}

	// connect to OPC server via ProgID
	public bool DoConnect( string progid )
		{
		try
			{
			theSrv.Connect( progid );
			Thread.Sleep( 100 );
			theSrv.SetClientName( "DirectOPC " + thisprocess.Id );	// set my client name (exe+process no)

			SERVERSTATUS sts;
			theSrv.GetStatus( out sts );

			// get infos about OPC server
			StringBuilder sb = new StringBuilder( sts.szVendorInfo, 200 );
			sb.AppendFormat( " ver:{0}.{1}.{2}", sts.wMajorVersion, sts.wMinorVersion, sts.wBuildNumber );
			txtServerInfo.Text = sb.ToString();

			// set status bar text to show server state
			sbpTimeStart.Text = DateTime.FromFileTime( sts.ftStartTime ).ToString();
			sbpStatus.Text = sts.eServerState.ToString();
			}
		catch( COMException )
			{
			MessageBox.Show( this, "connect error!", "Exception", MessageBoxButtons.OK, MessageBoxIcon.Warning );
			return false;
			}
		return true;
		}


	public bool CreateGroup()
		{
		try
			{
			// add our only working group
			theGrp = theSrv.AddGroup( "OPCdotNET-Group", true, 500 );

			// add event handler for data changes
			theGrp.DataChanged += new DataChangeEventHandler( this.theGrp_DataChange );
			theGrp.WriteCompleted += new WriteCompleteEventHandler( this.theGrp_WriteComplete );
			}
		catch( COMException )
			{
			MessageBox.Show( this, "create group error!", "Exception", MessageBoxButtons.OK, MessageBoxIcon.Warning );
			return false;
			}
		return true;
		}

	// event handler: called if any item in group has changed values
	protected void theGrp_DataChange( object sender, DataChangeEventArgs e )
		{
		Trace.WriteLine( "theGrp_DataChange  id=" + e.transactionID.ToString() + " me=0x" + e.masterError.ToString( "X" ) );

		foreach( OPCItemState s in e.sts )
			{
			if( s.HandleClient != itmHandleClient )		// only one client handle
				continue;

			Trace.WriteLine( "  item error=0x" + s.Error.ToString( "X" ) );

			if( HRESULTS.Succeeded( s.Error ) )
				{
				Trace.WriteLine( "  val=" + s.DataValue.ToString() );

				txtItemValue.Text	= s.DataValue.ToString();		// update screen
				txtItemQual.Text	= OpcGroup.QualityToString( s.Quality );
				txtItemTimeSt.Text	= DateTime.FromFileTime( s.TimeStamp ).ToString();
				}
			else
				{
				txtItemValue.Text	= "ERROR 0x" + s.Error.ToString( "X" );
				txtItemQual.Text	= "error";
				txtItemTimeSt.Text	= "error";
				}
			}
		}

	// event handler: called if asynch write finished
	protected void theGrp_WriteComplete( object sender, WriteCompleteEventArgs e )
		{
		foreach( OPCWriteResult w in e.res )
			{
			if( w.HandleClient != itmHandleClient )		// only one client handle
				continue;

			if( HRESULTS.Failed( w.Error ) )
				txtItemWriteRes.Text	= "ERROR 0x" + w.Error.ToString( "X" );
			else
				txtItemWriteRes.Text	= "ok";
			}
		}


	public bool DoBrowse()
		{
		try
			{
			OPCNAMESPACETYPE	opcorgi = theSrv.QueryOrganization();

			// fill TreeView with all
			treeOpcItems.Nodes.Clear();
			TreeNode	tnRoot = new TreeNode( rootname, 0, 1 );
			if( opcorgi == OPCNAMESPACETYPE.OPC_NS_HIERARCHIAL )
				{
				theSrv.ChangeBrowsePosition( OPCBROWSEDIRECTION.OPC_BROWSE_TO, "" );	// to root
				RecurBrowse( tnRoot, 1 );
				}
			treeOpcItems.Nodes.Add( tnRoot );

			tnRoot.ExpandAll();			// expand all nodes ([+] -> [-])
			tnRoot.EnsureVisible();		// make the root visible

			// preselect root (dummy)
			treeOpcItems.SelectedNode = tnRoot;		// force treeOpcItems_AfterSelect
			}
		catch( COMException /* eX */ )
			{
			MessageBox.Show( this, "browse error!", "DoBrowse", MessageBoxButtons.OK, MessageBoxIcon.Warning );
			return false;
			}
		return true;
		}

	// recursively call the OPC namespace tree
	public bool RecurBrowse( TreeNode tnParent, int depth )
		{
		try
			{
			ArrayList lst;
			theSrv.Browse( OPCBROWSETYPE.OPC_BRANCH, out lst );
			if( lst == null )
				return true;
			if( lst.Count < 1 )
				return true;
		
			foreach( string s in lst )
				{
				TreeNode tnNext = new TreeNode( s, 0, 1 );
				theSrv.ChangeBrowsePosition( OPCBROWSEDIRECTION.OPC_BROWSE_DOWN, s );
				RecurBrowse( tnNext, depth + 1 );
				theSrv.ChangeBrowsePosition( OPCBROWSEDIRECTION.OPC_BROWSE_UP, "" );
			
				tnParent.Nodes.Add( tnNext );
				}
			}
		catch( COMException /* eX */ )
			{
			MessageBox.Show( this, "browse error!", "RecurBrowse", MessageBoxButtons.OK, MessageBoxIcon.Warning );
			return false;
			}
		return true;
		}


	public bool ViewItem( string opcid )
		{
		try
			{
			RemoveItem();		// first remove previous item if any

			itmHandleClient	= 1234;
			OPCItemDef[]	aD = new OPCItemDef[1];
			aD[0] = new OPCItemDef( opcid, true, itmHandleClient, VarEnum.VT_EMPTY );
			OPCItemResult[]		arrRes;
			theGrp.AddItems( aD, out arrRes );
			if( arrRes == null )
				return false;
			if( arrRes[0].Error != HRESULTS.S_OK )
				return false;

			btnItemMore.Enabled	= true;
			itmHandleServer		= arrRes[0].HandleServer;
			itmAccessRights		= arrRes[0].AccessRights;
			itmTypeCode			= VT2TypeCode( arrRes[0].CanonicalDataType );

			txtItemID.Text			= opcid;
			txtItemDataType.Text	= DUMMY_VARIANT.VarEnumToString( arrRes[0].CanonicalDataType );

			if( (itmAccessRights & OPCACCESSRIGHTS.OPC_READABLE) != 0 )
				{
				int		cancelID;
				theGrp.Refresh2( OPCDATASOURCE.OPC_DS_DEVICE, 7788, out cancelID );
				}
			else
				txtItemValue.Text = "no read access";

			if( itmTypeCode != TypeCode.Object )				// Object=failed!
				{
				// check if write is premitted
				if( (itmAccessRights & OPCACCESSRIGHTS.OPC_WRITEABLE) != 0 )
					btnItemWrite.Enabled = true;
				}
			}
		catch( COMException )
			{
			MessageBox.Show( this, "AddItem OPC error!", "ViewItem", MessageBoxButtons.OK, MessageBoxIcon.Warning );
			return false;
			}
		return true;
		}


	// remove previous OPC item if any
	public bool RemoveItem()
		{
		try
			{
			if( itmHandleClient != 0 )
				{
				itmHandleClient			= 0;
				txtItemID.Text			= "";		// clear screen texts
				txtItemValue.Text		= "";
				txtItemDataType.Text	= "";
				txtItemQual.Text		= "";
				txtItemTimeSt.Text		= "";
				txtItemSendValue.Text	= "";
				txtItemWriteRes.Text	= "";
				btnItemWrite.Enabled	= false;
				btnItemMore.Enabled		= false;

				int[]	serverhandles	= new int[1] { itmHandleServer };
				int[]	remerrors;
				theGrp.RemoveItems( serverhandles, out remerrors );
				itmHandleServer = 0;
				}
			}
		catch( COMException )
			{
			MessageBox.Show( this, "RemoveItem OPC error!", "RemoveItem", MessageBoxButtons.OK, MessageBoxIcon.Warning );
			return false;
			}
		return true;
		}





	/// <summary>
	/// Clean up any resources being used.
	/// </summary>
	protected override void Dispose( bool disposing )
		{
		if( disposing )
			{
			if (components != null) 
				{
				components.Dispose();
				}
			}
		base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(MainForm));
			this.txtItemDataType = new System.Windows.Forms.TextBox();
			this.btnItemWrite = new System.Windows.Forms.Button();
			this.label3 = new System.Windows.Forms.Label();
			this.txtServer = new System.Windows.Forms.TextBox();
			this.txtItemID = new System.Windows.Forms.TextBox();
			this.listOpcView = new System.Windows.Forms.ListView();
			this.hdrListCol1 = new System.Windows.Forms.ColumnHeader();
			this.hdrListCol2 = new System.Windows.Forms.ColumnHeader();
			this.opclisticons = new System.Windows.Forms.ImageList(this.components);
			this.txtServerInfo = new System.Windows.Forms.TextBox();
			this.sbpStatus = new System.Windows.Forms.StatusBarPanel();
			this.btnAbout = new System.Windows.Forms.Button();
			this.txtItemValue = new System.Windows.Forms.TextBox();
			this.txtItemWriteRes = new System.Windows.Forms.TextBox();
			this.opctreeicons = new System.Windows.Forms.ImageList(this.components);
			this.txtItemTimeSt = new System.Windows.Forms.TextBox();
			this.statusBarMain = new System.Windows.Forms.StatusBar();
			this.sbpTimeStart = new System.Windows.Forms.StatusBarPanel();
			this.sbpDummy = new System.Windows.Forms.StatusBarPanel();
			this.btnItemMore = new System.Windows.Forms.Button();
			this.label4 = new System.Windows.Forms.Label();
			this.label1 = new System.Windows.Forms.Label();
			this.label2 = new System.Windows.Forms.Label();
			this.treeOpcItems = new System.Windows.Forms.TreeView();
			this.txtItemSendValue = new System.Windows.Forms.TextBox();
			this.txtItemQual = new System.Windows.Forms.TextBox();
			((System.ComponentModel.ISupportInitialize)(this.sbpStatus)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.sbpTimeStart)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.sbpDummy)).BeginInit();
			this.SuspendLayout();
			// 
			// txtItemDataType
			// 
			this.txtItemDataType.Location = new System.Drawing.Point(336, 296);
			this.txtItemDataType.Name = "txtItemDataType";
			this.txtItemDataType.ReadOnly = true;
			this.txtItemDataType.Size = new System.Drawing.Size(184, 20);
			this.txtItemDataType.TabIndex = 8;
			this.txtItemDataType.Text = "";
			// 
			// btnItemWrite
			// 
			this.btnItemWrite.Enabled = false;
			this.btnItemWrite.Location = new System.Drawing.Point(296, 328);
			this.btnItemWrite.Name = "btnItemWrite";
			this.btnItemWrite.Size = new System.Drawing.Size(64, 24);
			this.btnItemWrite.TabIndex = 11;
			this.btnItemWrite.Text = "write!";
			this.btnItemWrite.Click += new System.EventHandler(this.btnItemWrite_Click);
			// 
			// label3
			// 
			this.label3.Location = new System.Drawing.Point(8, 276);
			this.label3.Name = "label3";
			this.label3.Size = new System.Drawing.Size(40, 16);
			this.label3.TabIndex = 12;
			this.label3.Text = "quality";
			this.label3.TextAlign = System.Drawing.ContentAlignment.TopRight;
			// 
			// txtServer
			// 
			this.txtServer.Location = new System.Drawing.Point(8, 8);
			this.txtServer.Name = "txtServer";
			this.txtServer.ReadOnly = true;
			this.txtServer.Size = new System.Drawing.Size(248, 20);
			this.txtServer.TabIndex = 0;
			this.txtServer.Text = "server";
			// 
			// txtItemID
			// 
			this.txtItemID.Location = new System.Drawing.Point(8, 240);
			this.txtItemID.Name = "txtItemID";
			this.txtItemID.ReadOnly = true;
			this.txtItemID.Size = new System.Drawing.Size(512, 20);
			this.txtItemID.TabIndex = 4;
			this.txtItemID.Text = "full";
			// 
			// listOpcView
			// 
			this.listOpcView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
																						  this.hdrListCol1,
																						  this.hdrListCol2});
			this.listOpcView.FullRowSelect = true;
			this.listOpcView.GridLines = true;
			this.listOpcView.HideSelection = false;
			this.listOpcView.Location = new System.Drawing.Point(264, 32);
			this.listOpcView.MultiSelect = false;
			this.listOpcView.Name = "listOpcView";
			this.listOpcView.Size = new System.Drawing.Size(256, 200);
			this.listOpcView.SmallImageList = this.opclisticons;
			this.listOpcView.TabIndex = 3;
			this.listOpcView.View = System.Windows.Forms.View.Details;
			this.listOpcView.SelectedIndexChanged += new System.EventHandler(this.listOpcView_SelectedIndexChanged);
			// 
			// hdrListCol1
			// 
			this.hdrListCol1.Text = "Items";
			this.hdrListCol1.Width = 128;
			// 
			// hdrListCol2
			// 
			this.hdrListCol2.Text = "ItemID";
			this.hdrListCol2.Width = 300;
			// 
			// opclisticons
			// 
			this.opclisticons.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit;
			this.opclisticons.ImageSize = new System.Drawing.Size(16, 16);
			this.opclisticons.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("opclisticons.ImageStream")));
			this.opclisticons.TransparentColor = System.Drawing.Color.Transparent;
			// 
			// txtServerInfo
			// 
			this.txtServerInfo.Location = new System.Drawing.Point(264, 8);
			this.txtServerInfo.Name = "txtServerInfo";
			this.txtServerInfo.ReadOnly = true;
			this.txtServerInfo.Size = new System.Drawing.Size(256, 20);
			this.txtServerInfo.TabIndex = 1;
			this.txtServerInfo.Text = "serverinfo";
			// 
			// sbpStatus
			// 
			this.sbpStatus.MinWidth = 32;
			this.sbpStatus.Text = "1";
			this.sbpStatus.ToolTipText = "status of OPC server";
			this.sbpStatus.Width = 192;
			// 
			// btnAbout
			// 
			this.btnAbout.BackColor = System.Drawing.Color.SandyBrown;
			this.btnAbout.Location = new System.Drawing.Point(456, 360);
			this.btnAbout.Name = "btnAbout";
			this.btnAbout.Size = new System.Drawing.Size(64, 24);
			this.btnAbout.TabIndex = 11;
			this.btnAbout.Text = "about...";
			this.btnAbout.Click += new System.EventHandler(this.btnAbout_Click);
			// 
			// txtItemValue
			// 
			this.txtItemValue.Location = new System.Drawing.Point(56, 296);
			this.txtItemValue.Name = "txtItemValue";
			this.txtItemValue.ReadOnly = true;
			this.txtItemValue.Size = new System.Drawing.Size(232, 20);
			this.txtItemValue.TabIndex = 7;
			this.txtItemValue.Text = "";
			// 
			// txtItemWriteRes
			// 
			this.txtItemWriteRes.Location = new System.Drawing.Point(368, 328);
			this.txtItemWriteRes.Name = "txtItemWriteRes";
			this.txtItemWriteRes.ReadOnly = true;
			this.txtItemWriteRes.Size = new System.Drawing.Size(152, 20);
			this.txtItemWriteRes.TabIndex = 8;
			this.txtItemWriteRes.Text = "";
			// 
			// opctreeicons
			// 
			this.opctreeicons.ColorDepth = System.Windows.Forms.ColorDepth.Depth24Bit;
			this.opctreeicons.ImageSize = new System.Drawing.Size(16, 16);
			this.opctreeicons.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("opctreeicons.ImageStream")));
			this.opctreeicons.TransparentColor = System.Drawing.Color.Transparent;
			// 
			// txtItemTimeSt
			// 
			this.txtItemTimeSt.Location = new System.Drawing.Point(336, 272);
			this.txtItemTimeSt.Name = "txtItemTimeSt";
			this.txtItemTimeSt.ReadOnly = true;
			this.txtItemTimeSt.Size = new System.Drawing.Size(184, 20);
			this.txtItemTimeSt.TabIndex = 6;
			this.txtItemTimeSt.Text = "";
			// 
			// statusBarMain
			// 
			this.statusBarMain.Location = new System.Drawing.Point(0, 399);
			this.statusBarMain.Name = "statusBarMain";
			this.statusBarMain.Panels.AddRange(new System.Windows.Forms.StatusBarPanel[] {
																							 this.sbpTimeStart,
																							 this.sbpStatus,
																							 this.sbpDummy});
			this.statusBarMain.ShowPanels = true;
			this.statusBarMain.Size = new System.Drawing.Size(542, 16);
			this.statusBarMain.SizingGrip = false;
			this.statusBarMain.TabIndex = 9;
			// 
			// sbpTimeStart
			// 
			this.sbpTimeStart.MinWidth = 20;
			this.sbpTimeStart.Text = "0";
			this.sbpTimeStart.ToolTipText = "time of opc server start";
			this.sbpTimeStart.Width = 128;
			// 
			// btnItemMore
			// 
			this.btnItemMore.Enabled = false;
			this.btnItemMore.Location = new System.Drawing.Point(8, 360);
			this.btnItemMore.Name = "btnItemMore";
			this.btnItemMore.Size = new System.Drawing.Size(64, 24);
			this.btnItemMore.TabIndex = 11;
			this.btnItemMore.Text = "more...";
			this.btnItemMore.Click += new System.EventHandler(this.btnItemMore_Click);
			// 
			// label4
			// 
			this.label4.Location = new System.Drawing.Point(8, 301);
			this.label4.Name = "label4";
			this.label4.Size = new System.Drawing.Size(40, 16);
			this.label4.TabIndex = 12;
			this.label4.Text = "value";
			this.label4.TextAlign = System.Drawing.ContentAlignment.TopRight;
			// 
			// label1
			// 
			this.label1.Location = new System.Drawing.Point(296, 276);
			this.label1.Name = "label1";
			this.label1.Size = new System.Drawing.Size(32, 16);
			this.label1.TabIndex = 12;
			this.label1.Text = "time";
			this.label1.TextAlign = System.Drawing.ContentAlignment.TopRight;
			// 
			// label2
			// 
			this.label2.Location = new System.Drawing.Point(296, 301);
			this.label2.Name = "label2";
			this.label2.Size = new System.Drawing.Size(32, 16);
			this.label2.TabIndex = 12;
			this.label2.Text = "type";
			this.label2.TextAlign = System.Drawing.ContentAlignment.TopRight;
			// 
			// treeOpcItems
			// 
			this.treeOpcItems.HideSelection = false;
			this.treeOpcItems.ImageList = this.opctreeicons;
			this.treeOpcItems.Location = new System.Drawing.Point(8, 32);
			this.treeOpcItems.Name = "treeOpcItems";
			this.treeOpcItems.SelectedImageIndex = 1;
			this.treeOpcItems.Size = new System.Drawing.Size(248, 200);
			this.treeOpcItems.TabIndex = 2;
			this.treeOpcItems.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeOpcItems_AfterSelect);
			// 
			// txtItemSendValue
			// 
			this.txtItemSendValue.Location = new System.Drawing.Point(8, 328);
			this.txtItemSendValue.Name = "txtItemSendValue";
			this.txtItemSendValue.Size = new System.Drawing.Size(280, 20);
			this.txtItemSendValue.TabIndex = 10;
			this.txtItemSendValue.Text = "";
			// 
			// txtItemQual
			// 
			this.txtItemQual.Location = new System.Drawing.Point(56, 272);
			this.txtItemQual.Name = "txtItemQual";
			this.txtItemQual.ReadOnly = true;
			this.txtItemQual.Size = new System.Drawing.Size(232, 20);
			this.txtItemQual.TabIndex = 5;
			this.txtItemQual.Text = "";
			// 
			// MainForm
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(542, 415);
			this.Controls.AddRange(new System.Windows.Forms.Control[] {
																		  this.txtItemWriteRes,
																		  this.label3,
																		  this.txtItemSendValue,
																		  this.label1,
																		  this.treeOpcItems,
																		  this.txtServer,
																		  this.btnItemWrite,
																		  this.txtItemQual,
																		  this.txtItemID,
																		  this.txtItemValue,
																		  this.label2,
																		  this.txtItemDataType,
																		  this.txtItemTimeSt,
																		  this.listOpcView,
																		  this.txtServerInfo,
																		  this.statusBarMain,
																		  this.label4,
																		  this.btnItemMore,
																		  this.btnAbout});
			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
			this.MaximizeBox = false;
			this.MinimizeBox = false;
			this.Name = "MainForm";
			this.Text = "OPC.NET";
			this.Closing += new System.ComponentModel.CancelEventHandler(this.MainForm_Closing);
			this.Activated += new System.EventHandler(this.MainForm_Activated);
			((System.ComponentModel.ISupportInitialize)(this.sbpStatus)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.sbpTimeStart)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.sbpDummy)).EndInit();
			this.ResumeLayout(false);

		}
		#endregion

	/// <summary>
	/// The main entry point for the application.
	/// </summary>
	[STAThread]
	static void Main()
		{
		Application.Run( new MainForm() );
		}

	private void MainForm_Activated( object sender, System.EventArgs e )
		{
		if( ! first_activated )		// workaround to show SelServer form !after! MainForm is visible
			{
			first_activated = true;
			opc_connected	= DoInit();
			}
		}


	public TypeCode VT2TypeCode( VarEnum vevt )
		{
		switch( vevt )
			{
			case VarEnum.VT_I1:
				return TypeCode.SByte;
			case VarEnum.VT_I2:
				return TypeCode.Int16;
			case VarEnum.VT_I4:
				return TypeCode.Int32;
			case VarEnum.VT_I8:
				return TypeCode.Int64;

			case VarEnum.VT_UI1:
				return TypeCode.Byte;
			case VarEnum.VT_UI2:
				return TypeCode.UInt16;
			case VarEnum.VT_UI4:
				return TypeCode.UInt32;
			case VarEnum.VT_UI8:
				return TypeCode.UInt64;

			case VarEnum.VT_R4:
				return TypeCode.Single;
			case VarEnum.VT_R8:
				return TypeCode.Double;

			case VarEnum.VT_BSTR:
				return TypeCode.String;
			case VarEnum.VT_BOOL:
				return TypeCode.Boolean;
			case VarEnum.VT_DATE:
				return TypeCode.DateTime;
			case VarEnum.VT_DECIMAL:
				return TypeCode.Decimal;
			case VarEnum.VT_CY:				// not supported
				return TypeCode.Double;
			}

		return TypeCode.Object;
		}

	private void MainForm_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
		if( ! opc_connected )
			return;
			
		if( theGrp != null )
			{
			theGrp.DataChanged -= new DataChangeEventHandler( this.theGrp_DataChange );
			theGrp.WriteCompleted -= new WriteCompleteEventHandler( this.theGrp_WriteComplete );
			RemoveItem();
			theGrp.Remove( false );
			theGrp = null;
			}

		if( theSrv != null )
			{
			theSrv.Disconnect();				// should clean up
			theSrv = null;
			}

		opc_connected	= false;
		}

	private void btnItemWrite_Click(object sender, System.EventArgs e)
		{
		try
			{
			txtItemWriteRes.Text = "";
			
			// convert the user text to OPC data type of item
			object[]	arrVal = new Object[1];
			arrVal[0] = Convert.ChangeType( txtItemSendValue.Text, itmTypeCode );

			int[]	serverhandles	= new int[1] { itmHandleServer };
			int		cancelID;
			int[]	arrErr;
			theGrp.Write( serverhandles, arrVal, 9988, out cancelID, out arrErr );

			GC.Collect();		// just for fun
			}
		catch( FormatException )
			{
			MessageBox.Show( this, "Invalid data format!", "opcItemDoWrite_Click", MessageBoxButtons.OK, MessageBoxIcon.Warning );
			return;
			}
		catch( OverflowException )
			{
			MessageBox.Show( this, "Invalid data range/overflow!", "opcItemDoWrite_Click", MessageBoxButtons.OK, MessageBoxIcon.Warning );
			return;
			}
		catch( COMException )
			{
			MessageBox.Show( this, "OPC Write Item error!", "opcItemDoWrite_Click", MessageBoxButtons.OK, MessageBoxIcon.Warning );
			return;
			}
		}

	private void listOpcView_SelectedIndexChanged(object sender, System.EventArgs e)
		{
		if( listOpcView.SelectedItems.Count != 1 )		// no selection
			return;

		ListViewItem	selitem = listOpcView.SelectedItems[0];
		selecteditem = selitem.Text;				// new selected item in ListView
		itmFullID = selitem.SubItems[1].Text;		// fully qualified OPC item namespace path

		ViewItem( itmFullID );		// show item data+attribs on screen
		}

	private void treeOpcItems_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
		{
		listOpcView.Items.Clear();
		RemoveItem();				// remove item from group

		try
			{
			theSrv.ChangeBrowsePosition( OPCBROWSEDIRECTION.OPC_BROWSE_TO, "" );	// to root

			if( e.Node.FullPath.Length > rootname.Length )		// check if it's only the dummy root
				{
				selectednode = e.Node.FullPath.Substring( rootname.Length + 1 );
				string[] splitpath = selectednode.Split( new char[] {'\t'} );	// convert path-string to string-array (separator)

				foreach( string n in splitpath )
					theSrv.ChangeBrowsePosition( OPCBROWSEDIRECTION.OPC_BROWSE_DOWN, n );	// browse to node in OPC namespace
				}
			else
				selectednode = "";

			// get all items at this node level
			ArrayList lst;
			theSrv.Browse( OPCBROWSETYPE.OPC_LEAF, out lst );
			if( lst == null )
				return;
			if( lst.Count < 1 )
				return;
			
			// enum+add all item names to ListView
			string[]	itemstrings = new string[ 2 ];
			foreach( string item in lst )
				{
				itemstrings[0] = item;
				itemstrings[1] = theSrv.GetItemID( item );
				listOpcView.Items.Add( new ListViewItem( itemstrings, 0 ) );
				}

			// preselect top item in ListView
			listOpcView.Items[0].Selected = true;
			}
		catch( Exception ex )		// exceptions MUST be handled
			{
			MessageBox.Show( this, "browse error! " + ex.ToString(), "Exception browsing namespace", MessageBoxButtons.OK, MessageBoxIcon.Warning );
			return;
			}
		}

	private void btnItemMore_Click( object sender, System.EventArgs e )
		{
		PropsForm	frmProps = new PropsForm( ref theSrv, itmFullID );		// create item properties form
		frmProps.ShowDialog( this );
		}

	private void btnAbout_Click(object sender, System.EventArgs e)
		{
		AboutForm	frmAbout = new AboutForm();			// show about dialog
		frmAbout.ShowDialog( this );
		}

}	// class MainForm

}	// namespace DirectOPCClient

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions