Challenge – Ninjascript C# interface with a C++ dll

Alright, here is the deal. I am trying to interface a C++ dll with an indicator written for the NinjaTrader platform (which is written in ninjascript…essentially C# with some platform specific code additions). TO make my dll work the way it is intended, I need to be able to pass a struct array from the indicator to the dll. In the indicator code, I am passing the struct array via ref. In the dll, I am trying to accept the struct array as a pointer. This allows me to edit the contents in the dll, without trying to figure out a way to pass a horde of information back to NinjaTrader. Basically, the dll receives the struct array pointer, which gives it access to the contents directly. Then, when the dll function returns a bool true flag to Ninja, it accesses the struct array and renders the information to the chart. Sounds simple right? I thought so too.

Here is the problem. NinjaTrader does not allow unsafe code. So, when I try to pass the struct array to the dll, and receive it as a pointer, it immediately crashes the platform. If I receive the struct array as a pointer to a ref (*&), then it works, but….once control is passed back to Ninja, all the edits done in the struct array are non-existent.

So, to speed up this process, I have created a very brief indicator, and dll code set which demonstrates what I am trying to do.
Here is the ninja indicator code:

[StructLayout(LayoutKind.Sequential)]
public struct TestStruct
{
    public int x, y;    
}
TestStruct[] test = new TestStruct[2];

protected override void OnBarUpdate()
{
    if(CurrentBar < Count - 2) {return;}
    test[0].x = 10;
    test[0].y = 2;
    test[1].x = 0;
    test[1].y = 0;

    Print(GetDLL.TestFunk(ref test));
    Print("X0: " + test[0].x.ToString() + "  Y0: " + test[0].y.ToString());
    Print("X1: " + test[1].x.ToString() + "  Y1: " + test[1].y.ToString());
}

class GetDLL
{
    GetDLL() {}
    ~GetDLL() {}
    [DllImport("testdll.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "TestFunk")]
    public static extern int TestFunk(
            [In,MarshalAs(UnmanagedType.LPArray)] ref TestStruct[] test );
}

And now the C++ dll code:

#define WIN32_LEAN_AND_MEAN
#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>

struct TestStruct
{
   int x, y;
};

extern "C" __declspec(dllexport) int __stdcall TestFunk( TestStruct *testy )
{
   testy[1].x = 20;
   testy[1].y = 9;
   int one = testy[1].x;
   int two = testy[1].y;

   return (one + two);
}

Now, please keep in mind, this code I have pasted in above WILL cause NinjaTrader to crash the moment you place the indicator on a chart and it becomes active. The only way I have been able to make it NOT crash is to change the arg in the C++ TestFunk function to either TestStruct *&testy or TestStruct **testy, noting that the . operators will have to be changed to -> also.

Now that I have said all that, does anyone know how to get around this limitation and get access to the actual pointer, so the dll can edit the actual values stored in the struct array, which will be reflected inside NinjaTrader….but not crash?


Source: dll

Leave a Reply