好吧,这里是交易。我试图将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