2

My application contains two sides - client side on c++ and server side on c#. I need client side to receive structure with lowest possible latency. So I want it to receive a pointer to a structure and avoid marshaling. Structure is something like that:

struct OrderAction
{
    OrderActionType actionType;
    uint UserId;
    int OrdersExecutorId;
    int InstrumentId;
    int StrategyId;
    ....

So I think i want to do this:

  1. Server c# side pass pointer to client c++ side.
  2. At c++ side read and process struct by received pointer.
  3. At c# side free resources (delete struct) if needed.

In future I plan to replace c# server side with c++ server side so I want client to be completely independent. Client shouldn't know that it called and used from c#.

Questions:

  • Should I use this algorithm?
  • If so then at step 1 should I allocate structure at managed memory or unmanaged memory?
  • What methods should I use and probably someone can link an example?
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Oleg Vazhnev
  • 23,239
  • 54
  • 171
  • 305
  • 2
    You should be able to use unsafe code to take a pointer to the struct and pass that to your p/invoke function. If the struct lives inside of an object, you will need to use `fixed(){}` to pin that object. If the p/invoke function is going to use the pointer after it returns, you need to take additional steps on the managed side to make sure the struct continues to exist at the same memory location for as long as the unmanaged code is going to use it. – cdhowie Sep 24 '13 at 19:31
  • @cdhowie thanks, do you have example of doing this? how can I create and initialize struct in c# and pass pointer to it to c++ so at c++ side I can just "cast" it to the same structure? – Oleg Vazhnev Sep 24 '13 at 19:45
  • @javapowered Why don't you let the p/invoke mechanism do it for you as I suggest in my answer? – David Heffernan Sep 24 '13 at 20:31
  • @DavidHeffernan it's interesting, thanks, i think i need try that! – Oleg Vazhnev Sep 24 '13 at 20:40

3 Answers3

2

You'll first need to double check that your struct is blittable. If the struct is not blittable then you cannot avoid marshalling of some form. As it stands, the struct in the question looks like it is blittable, given the fields that you have shown, and assuming that OrderActionType is an enum.

Then you simply need to pass the struct by ref and it will be pinned, and then the pinned address passed to the native code.

On the C++ side the code would look like this:

int __stdcall foo(OrderAction *orderAction)
{
    ....
}

On the C# side it looks like this:

[DllImport(@"MyLib.dll")]
static extern int foo(ref OrderAction orderAction);
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • C++ References probably have the same encoding for parameter passing as pointers (store the address), but I think officially p/invoke `ref` parameters map to pointers. – Ben Voigt Sep 24 '13 at 19:48
  • @BenVoigt You can do it either way. If `null` is not a valid parameter then it's more convenient with a reference. – David Heffernan Sep 24 '13 at 19:49
  • You're still doing the equivalent of `reinterpret_cast(&foo)` -- it may work on a particular version of a particular compiler, but I still wouldn't recommend it. – Ben Voigt Sep 24 '13 at 19:54
  • @BenVoigt Over an interop boundary, I'm not sure how relevant that argument is. P/invoke interop is compiler dependent. This is not COM with a well-specified binary ABI. Anyway, I changed the code to pass a pointer. I do take your point. – David Heffernan Sep 24 '13 at 20:05
  • It is a well-defined ABI as long as the function prototype is C-language compatible. P/invoke is not supposed to be compiler-dependent at all, only C++ "IJW" interop is. You DO need `extern "C"` as well, else the name will get mangled and p/invoke won't find it. – Ben Voigt Sep 24 '13 at 20:12
  • @BenVoigt P/invoke is certainly compiler dependent. There is no C ABI. One example I came across here on SO was a question where the ABI for struct return values differed between compilers. The GNU compiler used different ABI from the MS compiler. With a pragma or compiler option (cannot remember, possibly both were options), you could make the GNU compiler match the MS behaviour. Yes, extern "C" is needed, or a .def file. But we don't need to cover every last detail in this Q. – David Heffernan Sep 24 '13 at 20:20
  • Ok, I'll give you the case of structure-valued return type, but that's not covered in the stdcall calling convention document. If you stick to what's documented in your calling convention, you'll have consistent ABI. – Ben Voigt Sep 24 '13 at 20:24
  • @BenVoigt OK, thanks. Is there an official documentation of `stdcall` somewhere? – David Heffernan Sep 24 '13 at 20:25
  • There's [this](http://msdn.microsoft.com/en-us/library/984x0h58.aspx) but it seems to be in the compiler documentation rather than the OS. Looking for the OS version. – Ben Voigt Sep 24 '13 at 20:27
  • thank you! it's interesting, i will try that. remember i'm going to replace c# side to c++ so I need a solution that can be used to connect c++ server with c++ client too! – Oleg Vazhnev Sep 24 '13 at 20:43
  • i've tried and it works fine. are you sure that no extra structures created? how does this feature work? in c++ am I reading the same memory as in c#? – Oleg Vazhnev Sep 25 '13 at 12:11
  • So long as the struct is blittable, it is pinned and then a pointer to the pinned memory is passed to the native code. Pinning stops the .net GC moving the struct in memory. So, no copies are made. But you do need to double check that the struct is blittable. – David Heffernan Sep 25 '13 at 12:20
0

This can't possibly work as you described. A pointer is a memory refference. If you have a c# server that holds the structure that structure is local to the memory on that machine. A pointer can not be passed via the web and still be useful on another machine because the data has not moved.

I would take a look at WCF to pass data around in the windows world. If that doesn't work, another option would be JSON if this is web based.

Vulcronos
  • 3,428
  • 3
  • 16
  • 24
0

What you could do is write a C++/CLI wrapper over the native C++ code you want to call.

The managed C++/CLI wrapper could offer a method that takes a managed reference to the structure:

void DoStuff(OrderAction^ action)
{
 //call in the native code
}

EDIT: Some basic info about C++/CLI (just in case...) http://en.wikipedia.org/wiki/C%2B%2B/CLI

ds27680
  • 1,993
  • 10
  • 11
  • i would prefer to use P/Invoke if possible as i use it in all other places – Oleg Vazhnev Sep 24 '13 at 19:30
  • 2
    Fair enough, allthough I do not know why would you go through the pains of p/Invoke. I mean p/Invoke is good for many things (like accessing Windows API where no counterpart exists in .Net. But for what you want to do C++/CLI is probably better suited and certainly more comfortable. – ds27680 Sep 24 '13 at 19:35
  • i just need to pass a pointer to structure. I think it should be possible to do. I can pass void* from c++ to c# (IntPtr). So I think it must be possible to do reverse opperation... – Oleg Vazhnev Sep 24 '13 at 19:40