gpt4 book ai didi

c# - 挑战 - Ninjascript C# 接口(interface)与 C++ dll

转载 作者:行者123 更新时间:2023-11-30 03:52:00 25 4
gpt4 key购买 nike

好吧,这是交易。我正在尝试将 C++ dll 与为 NinjaTrader 平台编写的指标(用 ninjascript 编写...本质上是 C# 并添加了一些特定于平台的代码)连接起来。为了使我的 dll 按预期方式工作,我需要能够将结构数组从指标传递到 dll。在指标代码中,我通过 ref 传递结构数组。在 dll 中,我试图接受结构数组作为指针。这使我能够编辑 dll 中的内容,而无需尝试找出将大量信息传回 NinjaTrader 的方法。基本上,dll 接收结构数组指针,这使它可以直接访问内容。然后,当 dll 函数向 Ninja 返回一个 bool true 标志时,它会访问结构数组并将信息呈现给图表。听起来很简单吧?我也是这么想的。

问题来了。 NinjaTrader 不允许不安全的代码。因此,当我尝试将结构数组传递给 dll 并将其作为指针接收时,它会立即使平台崩溃。如果我收到作为指向 ref (*&) 的指针的结构数组,那么它可以工作,但是......一旦控制权传回 Ninja,在结构数组中完成的所有编辑都不存在。

因此,为了加快这个过程,我创建了一个非常简短的指标和 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 函数中的 arg 更改为 TestStruct *&testyTestStruct **testy,并指出. 运算符也必须更改为 ->

既然我已经说了这么多,有没有人知道如何绕过这个限制并访问实际指针,这样 dll 就可以编辑存储在结构数组中的实际值,这将反射(reflect)在 NinjaTrader 中。 ..但没有崩溃?

最佳答案

万岁!我终于想通了。先把相关代码贴出来,我再解释。

首先是 C#/Ninjascript

public class TestIndicator : Indicator
{
[StructLayout(LayoutKind.Sequential)]
public struct TestStruct { public int x, y; }
static TestStruct[] testy = new TestStruct[2];

protected override void OnBarUpdate()
{
if(CurrentBar < Count - 2) {return;}

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

class GetDLL
{
GetDLL() {}
~GetDLL() {}
[DllImport("testdll.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "TestFunk")]
public static extern void TestFunk( ref TestStruct testy );
}
}

C++ 代码:

struct TestStruct { int x, y; };

extern "C" __declspec(dllexport) void __stdcall TestFunk( void *t)
{
TestStruct* ptE = (TestStruct*)t;
ptE->x = 10; ptE->y = 2;
ptE++;
ptE->x = 20; ptE->y = 9;
}

首先,我必须使用 newstruct 数组声明为 static,在堆上为其指定一个固定的内存位置。然后我将它作为 ref 传递给我的 C++ dll。

在 dll 内部,arg 被捕获为 void* 数据类型。接下来,我将 arg 类型转换为 `TestStruct* 并将其存储在另一个指针变量中(以保持我的零元素引用完好无损)。

从那时起,我有一个引用元素零的指针,我可以使用它来编辑结构数组中元素零处的值。要访问以下元素,我需要做的就是增加指针。一旦我这样做了,我就可以访问数组中的第一个元素。

没有任何内容被传回 NinjaTrader,因为 dll 正在编辑原始内存位置中的实际值。无需传回任何东西,从而减少必要的 CPU 周期/内存操作……这是我的初衷。

希望这可以帮助陷入类似情况的人。

关于c# - 挑战 - Ninjascript C# 接口(interface)与 C++ dll,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30958449/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com