Click here to Skip to main content
13,295,243 members (73,488 online)
Click here to Skip to main content
Add your own
alternative version


144 bookmarked
Posted 21 May 2001

OPC and .NET with COM Interoperability

, 8 Jul 2001
Rate this:
Please Sign up or sign in to vote.
How to access OPC (OLE for Process Control) from .NET with advanced COM interop

Sample Image


In industrial automation, OPC (OLE for Process Control, see is the primary COM component interface used to connect devices from different manufactures. The OPC standard is defined at 'two different layers' of COM/DCOM. First, as a collection of COM custom interfaces, and secondly as COM-automation compliant components/wrappers. For some reasons and applications, it is preferable to use the custom interface directly.

We will show you in this article how to access OPC servers with custom interfaces and how to write an OPC client in .NET.

The problem

The new Microsoft .NET Framework will provide some interoperability layers and tools to reuse a large part of the existing COM/ActiveX/OCX components, but with some strong limitations. While automation compliant COM objects will be nicely imported (as referenced COM objects inside Visual Studio .NET, or with the TLBIMP tool), pure custom COM interfaces will not work.

To understand the issues with COM custom interfaces and the .NET framework, we must first analyze, why automation components can be used immediately. Visual Studio .NET relies on the information found in a type-library for every imported COM component (e.g. the library generated by MIDL-compiler, named *.TLB). The problem is now, type libraries can only contain automation compliant information. So if we compile a custom-interface IDL file, the generated TLB misses very important type descriptions, especially the method call parameter size (e.g. of arrays). At the time of .NET Beta2, there's unfortunately no tool (like 'IDLIMP') to import custom interface IDL files.

Example: Since the MIDL compiler does not propagate size_is information to the type library, the marshaler doesn't know an array length and translates int[] to ref int.

One first solution would be to edit the assembly produced by TLBIMP (using ILDASM), and replace ref int with int[], and then compile IL back again with ILASM.

But if we look at some very custom IDL files, we also find methods with parameters like foo( int **arraybyref ) where arrays are passed by reference (caller allocates the memory)! Hand editing IL code won't work here, there's no marshaling signature for this. Currently, we must use one of two different workarounds:

  • Write a custom marshaler (e.g. in Managed C++)
  • Or the way we used, write a marshaling helper class (in C#)

The solution, first step

We have to rewrite our custom IDL file in a managed language code, here C#. Note this can be a very time consuming work! every method of all interfaces have to be coded in C#, and the critical (custom) parameters must be declared completely different. We found there's often no way around the use of the special IntPtr type.

Let's look at a sample method (from an OPC custom interface IDL):

  [in]                        DWORD            dwCount,
  [in,  size_is( dwCount)]    OPCITEMDEF     * pItemArray,
  [out, size_is(,dwCount)]    OPCITEMRESULT ** ppAddResults,
  [out, size_is(,dwCount)]    HRESULT       ** ppErrors    );

Redefined in C#, looks now like this:

int AddItems(
  [In]       int       dwCount,
  [In]       IntPtr    pItemArray,
  [Out]  out IntPtr    ppAddResults,
  [Out]  out IntPtr    ppErrors );

As you can see, we loose many type information by declaring parameters as IntPtr!

Another point is the default exception mapping of .NET: as custom interface methods return HRESULT values, failed calls will be converted by the .NET marshaller to exceptions of type COMException. Further, some COM methods will also return other success codes besides S_OK, mainly S_FALSE. With the default mapping, this hint return value will be lost.

To bypass exception mapping, declare the interface with special signature attributes. See at the code below for the head of the final interface declaration:

  [ComVisible(true), ComImport,
  InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IOPCItemMgt
  int AddItems(
    [In]       int       dwCount,
    [In]       IntPtr    pItemArray,
    [Out]  out IntPtr    ppAddResults,
    [Out]  out IntPtr    ppErrors );

The solution, second step

To use the interfaces we declared as above, it is recommended to write some wrapper classes. But more important, this wrapper now has to do all the custom marshaling, e.g. for all IntPtr parameters. So the wrapper must reconstruct the information we lost. Managed marshaling code makes use of the framework services provided in the System.Runtime.InteropServices namespace, especially the Marshal class. We found the following methods as useful for this:

AllocCoTaskMem() FreeCoTaskMem() SizeOf()manage COM native memory (as pointed to by IntPtr)
StructureToPtr() PtrToStructure() DestroyStructure()marshaling of simple structures
ReadInt32() WriteInt32() Copy()read/write to native memory (also -Byte/Int16/Int64)
PtrToStringUni() StringToCoTaskMemUni()string marshaling
GetObjectForNativeVariant() GetNativeVariantForObject()conversions between VARIANT and Object
ThrowExceptionForHR()map HRESULT to exception and throw
ReleaseComObject()finally, release COM object

To get the idea, see a simplified excerpt for the sample method AddItems() we declared above - here we allocate native memory and marshal an array of structures into it:

IntPtr ptrdef = Marshal.AllocCoTaskMem( count * sizedefinition );
int rundef = (int) ptrdef;
for( int i = 0; i < count; i++ )
  Marshal.StructureToPtr( definitions[i], (IntPtr) rundef, false );
  rundef += sizedefinition;

int hresult = itemsinterface.AddItems( count, ptrdef, ... );
int rundef = (int) ptrdef;
for( int i = 0; i < count; i++ )
  Marshal.DestroyStructure( (IntPtr) rundef, typedefinition );
  rundef += sizedefinition;
Marshal.FreeCoTaskMem( ptrdef );


In the download package, you will find the complete interface declarations and a sample client application showing how to use them.

Please note:

  • First read the included whitepaper
  • To run this OPC client, you must have any OPC-DA 2.0 servers installed!

Useful links

OPC, the OPC logo, and OPC Foundation are trademarks of the OPC Foundation. .NET, the .NET logo, and Microsoft .NET are trademarks of the Microsoft Corporation.


The information in this article & source code are published in accordance with the Beta2 bits of the .NET Framework SDK).


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


About the Author

United States United States
No Biography provided

You may also be interested in...

Comments and Discussions

QuestionI have a problem very important Pin
FIRAT 201027-Nov-15 6:06
memberFIRAT 201027-Nov-15 6:06 
QuestionPlease help me ? Pin
FIRAT 201027-Nov-15 3:08
memberFIRAT 201027-Nov-15 3:08 
QuestionPlease help me ? Pin
FIRAT 201026-Nov-15 23:20
memberFIRAT 201026-Nov-15 23:20 
Questioncommunication between Siemens PLC (S71200) and the OPC server Pin
Member 1170571030-Oct-15 14:30
memberMember 1170571030-Oct-15 14:30 
Questionopcdotnetlib.dll Pin
Member 118907076-Aug-15 4:13
memberMember 118907076-Aug-15 4:13 
AnswerRe: opcdotnetlib.dll Pin
T. Kouba20-Aug-15 5:39
memberT. Kouba20-Aug-15 5:39 
QuestionHow to read or write on multiple tags? Pin
Member 1103619112-Dec-14 1:00
memberMember 1103619112-Dec-14 1:00 
QuestionGetting list of servers Pin
apoplex200819-Aug-13 12:43
memberapoplex200819-Aug-13 12:43 
NewsMy OPC Client Pin
hadihidayat29-Jul-13 21:33
memberhadihidayat29-Jul-13 21:33 
QuestionOPCdotNETLib - How to add wrong items but still be able to read the good ones on the same OPCGroup? Pin
Member 840510625-Apr-13 2:37
memberMember 840510625-Apr-13 2:37 
Hello, guys.
I am facing a big issue and couldn't get it to work yet.
Well, first of all, I can read, write, whatever I want with this nice class. I am using WinXP and RSLinx OPC Server.

The problem is when I purposely add some wrong ItemIDs in the middle of my array of items def.

Let's se this example:
PLC Tags:


If at least ONE OF THE ITEMS is wrong, then the whole OPCGroup becomes strange and it says all of my items have either BAD quality or retunrs "null".
Does anyone know how to solve this issue?
I have to add wrong items and even though, must see those good ones.


modified 25-Apr-13 7:59am.

AnswerRe: OPCdotNETLib - How to add wrong items but still be able to read the good ones on the same OPCGroup? Pin
AmiArt3-Feb-14 23:56
memberAmiArt3-Feb-14 23:56 
QuestionHow to write int[] in server Pin
cavasconcelos14-Feb-13 7:01
membercavasconcelos14-Feb-13 7:01 
QuestionHow to use Sync Read? What is OPCDATASOURCE? Pin
Member 969760131-Jan-13 0:22
memberMember 969760131-Jan-13 0:22 
AnswerRe: How to use Sync Read? What is OPCDATASOURCE? Pin
AmiArt4-Feb-13 20:31
memberAmiArt4-Feb-13 20:31 
QuestionTimestamp Pin
tassen11-Oct-12 20:18
membertassen11-Oct-12 20:18 
AnswerRe: Timestamp Pin
ArciI25-Aug-17 5:37
memberArciI25-Aug-17 5:37 
BugInvalidComObjectException Pin
Xiang Zhai29-Aug-12 17:29
memberXiang Zhai29-Aug-12 17:29 
QuestionNot Able to browse all items Pin
Abith24-Jul-12 3:08
memberAbith24-Jul-12 3:08 
QuestionOPC and safearray exception Pin
Member 77063569-May-12 6:48
memberMember 77063569-May-12 6:48 
GeneralMy vote of 5 Pin
manoj kumar choubey28-Feb-12 19:16
membermanoj kumar choubey28-Feb-12 19:16 
QuestionOPC Pin
anand.phaniraj10-Feb-12 4:46
memberanand.phaniraj10-Feb-12 4:46 
AnswerRe: OPC Pin
ZbynekZ24-Mar-14 0:22
memberZbynekZ24-Mar-14 0:22 
QuestionOPC client error while adding items in groups Pin
Learning WIX5-Feb-12 20:26
memberLearning WIX5-Feb-12 20:26 
AnswerRe: OPC client error while adding items in groups Pin
DevilGeek20-Feb-12 22:00
memberDevilGeek20-Feb-12 22:00 
GeneralRe: OPC client error while adding items in groups Pin
Member 840510625-Apr-13 2:34
memberMember 840510625-Apr-13 2:34 
QuestionIsuue regarding connection with OPC server Pin
Lijomon T George11-Jan-12 3:48
memberLijomon T George11-Jan-12 3:48 
QuestionCannot connect to server Pin
Member 77167887-Dec-11 10:09
memberMember 77167887-Dec-11 10:09 
QuestionHow to solve the error 0x80004002 ? Pin
Member 48083819-Oct-11 6:07
memberMember 48083819-Oct-11 6:07 
AnswerRe: How to solve the error 0x80004002 ? Pin
Member 840510625-Apr-13 2:15
memberMember 840510625-Apr-13 2:15 
QuestionDescription item [modified] Pin
cavasconcelos11-May-11 8:13
membercavasconcelos11-May-11 8:13 
GeneralConnecting to remote server Pin
Deathwing2324-Mar-11 15:42
memberDeathwing2324-Mar-11 15:42 
GeneralCan't register OPCdotNETLib.dll in Windows 7 Home Premium Pin
Okoro24-Aug-10 2:28
memberOkoro24-Aug-10 2:28 
GeneralRe: Can't register OPCdotNETLib.dll in Windows 7 Home Premium Pin
Member 840510625-Apr-13 2:09
memberMember 840510625-Apr-13 2:09 
GeneralRemote OPC Server ---- > ReadData ???? (datavalue, timestamp,quality ) Pin
FIRAT 201012-Aug-10 23:09
memberFIRAT 201012-Aug-10 23:09 
GeneralRe: Remote OPC Server ---- > ReadData ???? (datavalue, timestamp,quality ) Pin
Jan Hussaarts9-Nov-10 4:06
memberJan Hussaarts9-Nov-10 4:06 
GeneralRe: Remote OPC Server ---- > ReadData ???? (datavalue, timestamp,quality ) Pin
kavvis_21-Feb-11 22:30
memberkavvis_21-Feb-11 22:30 
GeneralRe: Remote OPC Server ---- > ReadData ???? (datavalue, timestamp,quality ) Pin
Member 840510625-Apr-13 2:21
memberMember 840510625-Apr-13 2:21 
GeneralMultiple Read Pin
ersin384-Dec-08 3:46
memberersin384-Dec-08 3:46 
GeneralFrozen Data detection Pin
harpreetsinghchd17-Nov-08 19:30
memberharpreetsinghchd17-Nov-08 19:30 
GeneralRe: Frozen Data detection Pin
Janislav Dimitrov14-Apr-10 4:21
memberJanislav Dimitrov14-Apr-10 4:21 
General[Message Deleted] Pin
Thiago Tozim31-Jul-08 9:05
memberThiago Tozim31-Jul-08 9:05 
GeneralRe: Just use Mega OPC Data Logger Pin
dimas197118-Oct-08 8:49
memberdimas197118-Oct-08 8:49 
GeneralProblem in connecting to Citect OPC Server Pin
mahmoodsalamah237-May-08 3:12
membermahmoodsalamah237-May-08 3:12 
GeneralRe: Problem in connecting to Citect OPC Server Pin
mahmoodsalamah2311-May-08 5:39
membermahmoodsalamah2311-May-08 5:39 
GeneralRe: Problem in connecting to Citect OPC Server Pin
yesidh8-Jul-08 9:01
memberyesidh8-Jul-08 9:01 
GeneralRe: Problem in connecting to Citect OPC Server Pin
mahmoodsalamah2316-Dec-08 9:23
membermahmoodsalamah2316-Dec-08 9:23 
GeneralHelp please Pin
megdouli2-May-08 5:01
membermegdouli2-May-08 5:01 
GeneralRe: Help please Pin
rockeylau11-Mar-10 21:44
memberrockeylau11-Mar-10 21:44 
GeneralCan.t Browse OPC Items Pin
Okoro28-Apr-08 23:20
memberOkoro28-Apr-08 23:20 
GeneralRe: Can.t Browse OPC Items Pin
Magnitudo8-Dec-09 10:23
memberMagnitudo8-Dec-09 10:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.171207.1 | Last Updated 9 Jul 2001
Article Copyright 2001 by VISCOM .NET Team
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid