C# interop with unmanaged code is not nearly as difficult in practice as it sounds on paper. Most of the interop I have done has been COM (to/from managed code) but for my current freelance gig I need to call from C# into an ANSI C DLL.
I wrote a few simple ANSI C functions to act as the interface to my managed code, just to save some work. I could call them fine. Crucially, I could pass in ANSI strings and get them back.
Then I started getting an AccessViolationException "Attempted to read or write protected memory". I was positive that I had annotated the ANSI C code correctly to export the functions. The C# code had the appropriate DllImport decorations. C# and ANSI C thought the function was CDECL. Everything looked just fine.
The symptoms were downright peculiar. If I declared a local variable in the ANSI C function that I was calling the code threw the exception. If I attempted to call another function from inside the ANSI C function the code threw the exception.
As with so many things, it boiled down to an incorrect setting in the project file, a residual glitch from the fact that I first produced an EXE to exercise the code and then flipped to producing a DLL.
Along the way I learned that I don't need to mess about with IntPtr allocation and freeing. When I have a mutable string (e.g. the result is returned in a char* parameter), I can create a StringBuilder with the appropriate size and pass that from C#. C# marshals it for me.
Showing posts with label interop. Show all posts
Showing posts with label interop. Show all posts
Thursday, 5 March 2009
Tuesday, 8 July 2008
DotNet Stream to IStream
Lately I have been grafting some new cloth on to our legacy code. In this case, that means writing C# COM servers that get called from legacy Delphi.Win32 code.
I have been taking the various files that together comprise a user's model of the process flow in their organization and bundling them together using System.IO.Packaging (a nice wrapper on a ZIP file).
In all the places in the legacy Delphi code where it might try to get a TFileStream (Delphi people like to start their class names with the letter T) it will instead be getting a TOleStream on a C# object that implements IStream.
Here's the kicker. C# Stream objects don't implement IStream so you need a wrapper. Blech. Luckily for me, Oliver Sturm has already posted a partial solution (it implements Read but not Write) here so I was spared too much grief. Then it was just a matter of regenerating the Delphi wrappers for the assembly and now we're as good as gold, as they say in this country.
I have been taking the various files that together comprise a user's model of the process flow in their organization and bundling them together using System.IO.Packaging (a nice wrapper on a ZIP file).
In all the places in the legacy Delphi code where it might try to get a TFileStream (Delphi people like to start their class names with the letter T) it will instead be getting a TOleStream on a C# object that implements IStream.
Here's the kicker. C# Stream objects don't implement IStream so you need a wrapper. Blech. Luckily for me, Oliver Sturm has already posted a partial solution (it implements Read but not Write) here so I was spared too much grief. Then it was just a matter of regenerating the Delphi wrappers for the assembly and now we're as good as gold, as they say in this country.
Subscribe to:
Posts (Atom)