views:

685

answers:

3

Hi, I have a legacy DLL written in C that I'd like to call from a C# .NET application. The problem is that the DLL interface for the C DLL is fairly complicated. It's something like this:

__declspec(dllexport) void __stdcall ProcessChunk(
    void *p_prochdl,
    const BIG_INPUT_STRC *p_inparams,
    BIG_OUTPUT_STRC *p_outparams
);

The BIG_INPUT_STRC/BIG_OUTPUT_STRC contain all kinds of things... pointers to buffer arrays, enumerated parameters, integer parameters, etc. In short, they're complicated.

First question: Is there an easy way to get all of the structure information that is contained in the DLL header file into the C# class, or do you need to literally copy and paste everything to C# and re-define it? This seems redundant.

Related to that, what is the correct way to pass structs into the unmanaged DLL from C#?

Finally, is there an example of how to correctly pass buffer arrays from C# into the unmanaged DLL? Alternatively, how can I pass a two-dimensional array into the DLL?

Thanks, -Greg

+2  A: 

Its quite straight forward to do this soft of thing in C# using P/Invoke.

I belive you are going to have to define the data structures in C# manually.

I would reccomend you take a look at this MSDN article on the subject

Tim
+1  A: 

You'll need to extensively use .net marshalling. First you need to re-define C structs in your C# code, then make sure everything gets marshalle properly using the MarshalAs attribute.

If you need to pass a pointer-to-structure in C# back to the C function you can use the Marshal.StructToPtr function.

Buffer arrays, assuming they're defined as byte[] you can marshal using the following technique:

byte[] buffer = ...;
fixed(byte *pBuffer = buffer)
{
   // do something with the pBuffer
}

The fixed statement makes sure that the bufffer doesn't get moved in the memory by the garbage collector, making the pointer within the statement 'fixed' or 'pinned'.

As for the multi dimensional arrays, it depends on the underlying C implementation, you might for example work with a pointer to the array and adjust the position based on the number of dimension and the number of elements in each dimension like:

someValue = buffer[(elementsPerDimensions * x) + y];

From your description it already seems pretty complicated, have you considered making your library COM friendly?

arul
A: 

What a pill.

  1. I'd avoid trying to make the library COM friendly. That's more trouble than its worth.

  2. I'd build a second native library with functions designed to be P/INVOKED to build up the records for the first and call it.

Alternately, you could make a C++ native/managed library to handle the marshaling.

Joshua
Avoid COM why? The interoperability is superb, there's nearly nothing that needs to be done but import the interfaces.
arul
I've seen too many senseless COM-related deadlocks, even between multiple processes using different COM dlls. I also think that the work required to make a complex native interface COM friendly is hardly less than what I already described.
Joshua