C header to c#

G

Guest

I have dynamic library in a DLL. With a standard c header file to it. Writing
a simple COM-wrapper in Visual Basic 6 was quite simple, and proves effective
in providing my library's functionality to VB and VBScript.

Now I want to let the .NET developers have just as much of a breeze, but it
has proven not to be quite as easy. I want to write the .net class library in
c# and I can not change the original API in anyway as it is a deployed
application.

Lets say I have this defined in a C header:

// Some constants
#define NAME_LEN 16
// A very simple struct
typedef struct {
int id;
char name[NAME_LEN];
} session;
// And a function taking various arguments.
int login(session *sess, int orgnr, char *name);

The approach I am heading for is to have the C API in a private wrapper
class in the name-space, and then write new wrapper classes in c# with calls
to static methods in this class. I think it would hide the inner workings
good from the end user and keep it simple for me (It worked for the Java,
C++, Objective-C, Perl and COM wrappers already done at least).

Trouble #1:
#define NAME_LEN 16
This would translate to:
private const int NAME_LEN = 16;
If it could be done in the name space, now I can not so I have to go with
public in the private wrapper class or make it part of a private enum in the
name space. What method is preferred?

Trouble #2:
The struct, something like this:
[StructLayout(LayoutKind.Explicit)]
public struct session {
[FieldOffset(0)] public int id;
[FieldOffset(4)] public byte[] name = new byte[wrapperclass.NAME_LEN];
}
I go for byte instead of char as char is Unicode in c# and I need basic
LATIN1 encoding. But I somehow doubt this will do anyway, as my bet is that
byte[] and new byte[...] does quite allot of magic behind the scene that is
as far from what C does as one can come :). So question is; how do I define
the struct to be compatible in c#?

Trouble #3:
The call, first argument:
[DllImport("thelib.dll")]
public static extern int login(session* sess, int orgnr, byte *name);
Is syntactically correct, but it is the best way? I see the keyword ref
being mentioned allot, and I think it would work just as well in this case.
But I want to pass around the struct allot (Being a session struct it will be
used by all other functions as one can guess) so using a pointer seams more
natural?

Trouble #4:
The call, third argument:
[DllImport("thelib.dll")]
public static extern int login(session* sess, int orgnr, byte *name);
Me no like it at all, does not seem to me like the right way to do it. The
string class have a ToCharArray method, but that on is Unicode as well. And
as I said, Unicode is no good to me, only LATIN1. So how do I pass simply
c-strings? (And retrieve them?).

Lots of questions, so I send out a lot of thanks in advance :).

regards
//Fredrik Olsson
 
N

Nicholas Paldino [.NET/C# MVP]

Fredrik,

See inline:
Trouble #1:
#define NAME_LEN 16
This would translate to:
private const int NAME_LEN = 16;
If it could be done in the name space, now I can not so I have to go with
public in the private wrapper class or make it part of a private enum in
the
name space. What method is preferred?

You could declare this as internal, then only classes inside your
assembly can use it, but it won't be visible outside of the assembly.
Trouble #2:
The struct, something like this:
[StructLayout(LayoutKind.Explicit)]
public struct session {
[FieldOffset(0)] public int id;
[FieldOffset(4)] public byte[] name = new byte[wrapperclass.NAME_LEN];
}
I go for byte instead of char as char is Unicode in c# and I need basic
LATIN1 encoding. But I somehow doubt this will do anyway, as my bet is
that
byte[] and new byte[...] does quite allot of magic behind the scene that
is
as far from what C does as one can come :). So question is; how do I
define
the struct to be compatible in c#?

For your application, you are going to have to do this. Publically, you
would want to expose your structure like this:

public struct session
{
public int id;
public string name;
}

Then, internally, you would use another structure which is passed to the
interop layer, like so:

[StructLayout(LayoutKind.Sequential)]
internal struct InternalSession
{
public int id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=wrapperclass.NAME_LEN)]
public byte[] name;
}

Then your wrappers would take a type of session, and you would convert
the string into an array of bytes using the encoding classes in the
System.Text namespace. You could make this a single structure, and use a
custom marshaler as well (which is more elegant, IMO).
Trouble #3:
The call, first argument:
[DllImport("thelib.dll")]
public static extern int login(session* sess, int orgnr, byte *name);
Is syntactically correct, but it is the best way? I see the keyword ref
being mentioned allot, and I think it would work just as well in this
case.
But I want to pass around the struct allot (Being a session struct it will
be
used by all other functions as one can guess) so using a pointer seams
more
natural?

You can only use the pointer if you are using unsafe code, and I don't
think you want to force your clients to do that. What you should do is use
the ref keyword, like so:

[DllImport("thelib.dll")]
public static extern int login(ref InternalSession sess, int orgnr, byte[]
name);
Trouble #4:
The call, third argument:
[DllImport("thelib.dll")]
public static extern int login(session* sess, int orgnr, byte *name);
Me no like it at all, does not seem to me like the right way to do it. The
string class have a ToCharArray method, but that on is Unicode as well.
And
as I said, Unicode is no good to me, only LATIN1. So how do I pass simply
c-strings? (And retrieve them?).

You will have to have a wrapper for this that will convert to the proper
encoding (through the System.Text namespace).
Lots of questions, so I send out a lot of thanks in advance :).

regards
//Fredrik Olsson

You might also want to revise the names on the public types. I suggest
you take a look at the guidelines for public naming conventions.

Hope this helps.
 
G

Guest

You might also want to revise the names on the public types. I suggest
you take a look at the guidelines for public naming conventions.

Hope this helps.

It helped very much, I already got all constants, structs and function
calles declared. At elast the compiler does not complain :). And I have been
able to login and get the basic user information fromt he server through c#.
So it is a major step forward, and a big thank you for pushing me in the
right direction!

regards
//Fredrik Olsson
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top