2

I have a function in C with this signature:

int addPos(int init_array_size, 
           int *cnt, 
           int *array_size, 
           PosT ***posArray, 
           char *infoMsg);

and here is what PosT looks like:

typedef union pu
{
    struct  dpos   d;
    struct  epo    e;
    struct  bpos   b;
    struct  spos   c;
} PosT ;

What's the best way to call this method in C# via P/Invoke? Do I need to define a class in C# representing PosT? How do I pass PosT ***posArray parameter across from C# to C?

7
  • 1
    I know this isn't productive toward answering the question, but why on earth does that C function declaration have so many parameters? That could easily be wrapped by a simple structure. I believe there's some sample code for marshalling a structure in an answer here: stackoverflow.com/questions/1985067/… Commented Dec 19, 2012 at 17:07
  • 1
    What exactly is the hPtr parameter. Just knowing its type is not enough information. Commented Dec 19, 2012 at 17:10
  • 2
    Roll up a nice fat news paper. I'd recommend the New York Times Sunday edition. Go find the programmer that wrote that code and give him a good whack over the head with the paper. That ought to keep you inspired for a while as you try to get this monstrosity going. Commented Dec 19, 2012 at 17:14
  • original post eddited now, with less parameters, this is an API I need to call, so I have to accept it as is. Commented Dec 19, 2012 at 17:40
  • 1
    You are going to need to answer the question I asked, which quetzalcoatl elaborated on. Until you do so, nobody can help you. Commented Dec 19, 2012 at 20:28

2 Answers 2

2

You have described how the PosT looks like, but this is not enough. First, have to know what the function expects to be passed as the ***PosT argument, and only THEN you can think of invoking it from C++ or C# side.

I know that probably does not fit your wishes, but please look:

PosT p;
PosT* ptr = &p;
PosT** ptr2 = &ptr;
PosT*** ptr3 = &ptr2;
func(...., ptr3, ...); // OK!?


PosT* ptr = new PosT[123];
PosT** ptr2 = &ptr;
PosT*** ptr3 = &ptr2;
func(...., ptr3, ...); // OK!?


PosT** ptr2 = new PosT[5];
for(int i=0;i<5;++i) ptr2[i] = new PosT[123];
PosT*** ptr3 = &ptr2;
func(...., ptr3, ...); // OK!??

And so on. Which one in-memory structure that I have quickly built is correct for that function? This is what determines the datatype that you will have to pass from the C# side.

If the function takes a thing you'd call a "mutable reference to jagged aray" (so the LAST example I provided), so the P/Invoke declaration would be:

[..extern..]
void func(....., ref PosT[][] posArray, ...);

invoked similar to:

func(...., new PosT[][] { 
         new PosT[] { new PosT{ d = ... }, new PosT{ d = ... }, ... },
         new PosT[] { new PosT{ d = ... }, new PosT{ d = ... }, ... },
         ... },
    .... );

but, please, first check what this function expects. With * there are really too many posibilities to just guess. You say it is from some API - check in its docs first! Tell us what exactly this function expects and me/someone will tell you how to build such POD in C#. Other way round it will not work! :)

PS. sorry for crappy C++/C# code, I'm in haste and only had a few minutes to write this:/

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks quetza I appreciate it, in my C program I call it like this: variable declaration: PosT **posArray = NULL; and for the call: Addpos(..., &posArray,..) and addPos() will allocate memory for it, populate it and will return it. and then I have another function that does the deallocation.
Hi quetzalcoatl I have added a cleaner and more detailed version of the question here: stackoverflow.com/questions/13974790/… I appreciate your help.
1

Question #1 do I need to define a class in CSharp representing PosT?
You should define PosT as a struct in c#. Since this a union struct you will need to apply the StructLayout attribute, and fully define your other structs. It might look something like this:

struct  dpos { };
struct  epo  { };
struct  bpos { };
struct  spos { };
[System.Runtime.InteropServices.StructLayout(
    System.Runtime.InteropServices.LayoutKind.Explicit, Size=99)]
struct PosT {
    [System.Runtime.InteropServices.FieldOffset(0)] dpos   d;
    [System.Runtime.InteropServices.FieldOffset(0)] epo    e;
    [System.Runtime.InteropServices.FieldOffset(0)] bpos   b;
    [System.Runtime.InteropServices.FieldOffset(0)] spos   c;
    };

** Note that the "Size=99" isn't correct. Ideally, you should set this size to the number of bytes used by the largest enclosed struct.

Question #2- how do I pass PosT ***posArray parameter across frm CSharp to C?
You have to be really careful doing this sort of thing, especially if you expect to allocate the memory for posArray under C#. You don't want to pass a buffer to C that the .NET GC is about to move/change. If C is returning the buffer you should be ok (but you will leak memory if there isn't a C function to let you release the memory). You should take a look at Default Marshaling for Arrays and www.pinvoke.net might have some examples. If you are sending the posArray buffer from C# to C you are going to have to resort to an unsafe context (see below). I'm not sure exactly how to handle that level or redirection. Your cnt and array_size can be handled using the 'ref' keyword.

Question #3- How do I specify marshaling for it all?
Take a look at the links above especially the Default Marshaling for Arrays. You might also need to just play about with some test code, break after the call and use the immediate window to investigate the structures.


Remember

You can pretty much do a straight (c-like) call if you compile c# using the "UNSAFE" switch. For example:

unsafe public MainWindow() {
    InitializeComponent();
    int abc = 4;
    int* abcPtr = &abc;
    *abcPtr = 8;

    fixed (PosT* gog = new PosT[30]) {
        PosT* gogPtr = (gog + 1);
        }
    }

You have to be very careful because C# manages it's own memory and can move things on you (see 'fixed' above). I'm not recommending this but it's useful for quick and dirty sorts of things

Also if the API is defined in a tlb (table library) visual studio will usually offer to create the bindings for you via a stub dll (see tlbimp command)


Hopefully, someone can provide a more specific response but I think this info could at least start you down the road.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.