如何正确地将结构数组从 MQL4 传递到 C# DLL 库
How to correctly pass array of structs from MQL4 to C# DLL library
我正在用 MQL4
语言为 MetaTrader Terminal 4 编写脚本,它使用 C# DLL 库 获取更多数据加工。
我想做的是传递一个包含以下 MQL4
结构的数组:
struct marketUpdate
{
double openPrice;
double closePrice;
double highPrice;
double lowPrice;
int volume;
double pipValuePerLot;
int intervalLength;
string symbol;
string time;
};
到C# DLL
中的这个函数:
[DllExport("HistoricMarketData", CallingConvention.StdCall)]
public static int HistoricMarketData(
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] MarketUpdate[] unmanagedArray,
int length)
{
// further processing
}
这是MQL4
端的函数定义:
int HistoricMarketData(
marketUpdate &marketUpdates[],
int length);
这是 C#
一侧的结构:
[StructLayout(LayoutKind.Explicit)]
public struct MarketUpdate
{
[MarshalAs(UnmanagedType.R8)]
[FieldOffset(0)]
public double openPrice;
[MarshalAs(UnmanagedType.R8)]
[FieldOffset(8)]
public double closePrice;
[MarshalAs(UnmanagedType.R8)]
[FieldOffset(16)]
public double highPrice;
[MarshalAs(UnmanagedType.R8)]
[FieldOffset(24)]
public double lowPrice;
[MarshalAs(UnmanagedType.I4)]
[FieldOffset(32)]
public int volume;
[MarshalAs(UnmanagedType.R8)]
[FieldOffset(36)]
public double pipValuePerLot;
[MarshalAs(UnmanagedType.I4)]
[FieldOffset(44)]
public int intervalLength;
[MarshalAs(UnmanagedType.LPWStr)]
[FieldOffset(48)]
public string symbol;
[MarshalAs(UnmanagedType.LPWStr)]
[FieldOffset(60)]
public string time;
}
我的问题是从 MQL4
调用 HistoricMarketData
时它不起作用。该脚本要么使整个 MetaTrader 程序崩溃,要么抛出异常并失败。
如您所见,我正在使用 Robert Giesecke 的 Unmanaged Exports 库来使其正常工作,并且我正确地将 DLL
导入 MQL4
作为其他函数里面没有任何问题。
经过大量试验和错误后,我发现当我从结构中删除这 2 个字符串属性(symbol
和 time
)时,所有工作都按预期进行并且结构被正确传递给C#
函数。
所以我的问题是如何正确地将结构中的字符串从MQL4
传递到C#
?
我已经尝试将结构中 MarshalAs
注释处的 UnmanagedType
参数更改为其他字符串变体,但没有帮助。把两边的string
改成char[]
也没用。
如果有任何建议或帮助,我将不胜感激。
谢谢!
欢迎来到 MQL4
的狂野世界,其中 string
不是字符串,
而是 struct
所以,
这个,
不仅如此,
重新整合 MQL4
与 DLL
-s
造成了很多麻烦
我自己的攻略是:
1) 避免 MQL4
-strings,如果不是核心重要性,
2) 如果需要,通过 DLL
-proxy 实用函数传递它们,该函数处理所需的转换:
#import <dll> // DLL-native CallSignatures:
...
int mql4s_send ( int socket, uchar &text[] );
...
#import
// DLL-proxy with StringToCharArray() conversion:
int s_send ( int socket, string text ) { uchar textChar[]; StringToCharArray( text, textChar );
return ( mql4s_send ( socket, textChar ) );
}
无论如何,
宁愿阅读 MQL4
帮助,实际上 最好在每次 MetaTrader Build 更新后重新阅读 它(是的,我是说,新的帮助文件包含(至少)一些关于新 MQL4
功能的评论,没有其他简单的方法可以找到和了解这些功能——它节省了很多时间。随着代码库的维护,跨越超过几百人*年,我很清楚这种痛苦。
The following can't be used for parameters in imported functions:
·pointers;
·links to objects that contain dynamic arrays and/or pointers.
Classes, string arrays or complex objects that contain strings and/or dynamic arrays of any types cannot be passed as a parameter to functions imported from DLL.
但魔鬼隐藏在这样的细节中(间接禁止的功能):
...
Simple Structures
Structures that do not contain strings or objects of dynamic arrays are called simple structures; variables of such structures can be freely copied to each other, even if they are different structures. Variables of simple structures, as well as their array can be passed as parameters to functions imported from DLL.
我正在用 MQL4
语言为 MetaTrader Terminal 4 编写脚本,它使用 C# DLL 库 获取更多数据加工。
我想做的是传递一个包含以下 MQL4
结构的数组:
struct marketUpdate
{
double openPrice;
double closePrice;
double highPrice;
double lowPrice;
int volume;
double pipValuePerLot;
int intervalLength;
string symbol;
string time;
};
到C# DLL
中的这个函数:
[DllExport("HistoricMarketData", CallingConvention.StdCall)]
public static int HistoricMarketData(
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] MarketUpdate[] unmanagedArray,
int length)
{
// further processing
}
这是MQL4
端的函数定义:
int HistoricMarketData(
marketUpdate &marketUpdates[],
int length);
这是 C#
一侧的结构:
[StructLayout(LayoutKind.Explicit)]
public struct MarketUpdate
{
[MarshalAs(UnmanagedType.R8)]
[FieldOffset(0)]
public double openPrice;
[MarshalAs(UnmanagedType.R8)]
[FieldOffset(8)]
public double closePrice;
[MarshalAs(UnmanagedType.R8)]
[FieldOffset(16)]
public double highPrice;
[MarshalAs(UnmanagedType.R8)]
[FieldOffset(24)]
public double lowPrice;
[MarshalAs(UnmanagedType.I4)]
[FieldOffset(32)]
public int volume;
[MarshalAs(UnmanagedType.R8)]
[FieldOffset(36)]
public double pipValuePerLot;
[MarshalAs(UnmanagedType.I4)]
[FieldOffset(44)]
public int intervalLength;
[MarshalAs(UnmanagedType.LPWStr)]
[FieldOffset(48)]
public string symbol;
[MarshalAs(UnmanagedType.LPWStr)]
[FieldOffset(60)]
public string time;
}
我的问题是从 MQL4
调用 HistoricMarketData
时它不起作用。该脚本要么使整个 MetaTrader 程序崩溃,要么抛出异常并失败。
如您所见,我正在使用 Robert Giesecke 的 Unmanaged Exports 库来使其正常工作,并且我正确地将 DLL
导入 MQL4
作为其他函数里面没有任何问题。
经过大量试验和错误后,我发现当我从结构中删除这 2 个字符串属性(symbol
和 time
)时,所有工作都按预期进行并且结构被正确传递给C#
函数。
所以我的问题是如何正确地将结构中的字符串从MQL4
传递到C#
?
我已经尝试将结构中 MarshalAs
注释处的 UnmanagedType
参数更改为其他字符串变体,但没有帮助。把两边的string
改成char[]
也没用。
如果有任何建议或帮助,我将不胜感激。
谢谢!
欢迎来到 MQL4
的狂野世界,其中 string
不是字符串,
而是 struct
所以,
这个,
不仅如此,
重新整合 MQL4
与 DLL
-s
我自己的攻略是:
1) 避免 MQL4
-strings,如果不是核心重要性,
2) 如果需要,通过 DLL
-proxy 实用函数传递它们,该函数处理所需的转换:
#import <dll> // DLL-native CallSignatures:
...
int mql4s_send ( int socket, uchar &text[] );
...
#import
// DLL-proxy with StringToCharArray() conversion:
int s_send ( int socket, string text ) { uchar textChar[]; StringToCharArray( text, textChar );
return ( mql4s_send ( socket, textChar ) );
}
无论如何,
宁愿阅读 MQL4
帮助,实际上 最好在每次 MetaTrader Build 更新后重新阅读 它(是的,我是说,新的帮助文件包含(至少)一些关于新 MQL4
功能的评论,没有其他简单的方法可以找到和了解这些功能——它节省了很多时间。随着代码库的维护,跨越超过几百人*年,我很清楚这种痛苦。
The following can't be used for parameters in imported functions:
·pointers;
·links to objects that contain dynamic arrays and/or pointers.
Classes, string arrays or complex objects that contain strings and/or dynamic arrays of any types cannot be passed as a parameter to functions imported from DLL.
但魔鬼隐藏在这样的细节中(间接禁止的功能):
...
Simple Structures
Structures that do not contain strings or objects of dynamic arrays are called simple structures; variables of such structures can be freely copied to each other, even if they are different structures. Variables of simple structures, as well as their array can be passed as parameters to functions imported from DLL.