好吧,這裏是交易。我試圖將C++ dll與爲NinjaTrader平臺編寫的指示器(它是用ninjascript編寫的......基本上C#與一些特定於平臺的代碼添加)編寫的接口。爲了讓我的dll按照預期的方式工作,我需要能夠將指標中的結構數組傳遞給dll。在指標代碼中,我通過ref傳遞了結構數組。在DLL中,我試圖接受結構數組作爲指針。這使我能夠編輯dll中的內容,而不需要找出一種方法將大量信息傳回給NinjaTrader。基本上,dll接收結構數組指針,它可以直接訪問內容。然後,當dll函數向Ninja返回一個bool true標誌時,它訪問struct數組並將信息呈現給圖表。聽起來很簡單吧?我也是這麼想。挑戰-Ninjascript C#接口與C++ dll
這是問題所在。 NinjaTrader不允許使用不安全的代碼。所以,當我嘗試將結構數組傳遞給dll並將其作爲指針接收時,它立即崩潰了平臺。如果我將結構數組作爲指向ref(* &)的指針接收,那麼它可以工作,但是......一旦控制傳回忍者,在struct數組中完成的所有編輯都不存在。
因此,爲了加速這個過程,我創建了一個非常簡短的指示器,以及演示我正在嘗試執行的dll代碼集。 這裏是忍者指標代碼:
[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);
}
而且現在的C++ DLL代碼:
#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);
}
現在,請記住,這個代碼,我已經在上面粘貼會導致NinjaTrader崩潰的那一刻您將指標放置在圖表上並且它變爲活動狀態。我能夠使其不會崩潰的唯一方法是將C++ TestFunk函數中的參數更改爲TestStruct *&testy
或TestStruct **testy
,並指出.
運算符也必須更改爲->
。
現在我已經說過了,有沒有人知道如何解決這個限制並訪問實際的指針,所以dll可以編輯存儲在struct數組中的實際值,這將在NinjaTrader中反映出來。 ...但不會崩潰?
不使用不安全的代碼。這是託管(C#)和非託管(C++)代碼(即使用指針)之間最大的區別之一。 – SteveFerg
到目前爲止,這是我的結論。我不能動搖在C++端可以完成的任何事情來捕獲內存地址。 – MehZhure
根據您的約束,您可以始終傳遞數組或結構,並以格式返回字符串,您可以輕鬆地執行類似returnString.split(',')的操作來獲取所需內容。 – SteveFerg