Metatrader и Dll: работаем со структурами

Категория: Metatrader
Опубликовано 15.02.2014 09:39

Давно я не работал с MT4. Оказалось, они уже успели в него добавить поддержку MQL5.

Итак, задача: передача в dll структуры с данными и перезапись этих данных в библиотеке.

В качестве данных используем простые типы int и double. Для начала создадим структуру:

#property strict
struct TestStruct
{
    public:
        int p1;
        int p2;
        double p3;
        double p4;
};

Вызов длл будет осуществляться так:

#property strict 
#include <WindowControl/TestStruct.mqh>


#import "WindowControl.dll"
	void CallMe(TestStruct& ts);
#import

void OnStart()
{
	TestStruct ts;
	ts.p1 = 2;
	ts.p2 = 4;
	ts.p3 = 7.5;
	ts.p4 = 9.22;
	CallMe(ts);
	Print(ts.p1);
	Print(ts.p2);
	Print(ts.p3);
	Print(ts.p4);
}

В MQL4 частью закончили, теперь DLL. Пишем на шарпе, для экспорта функций используем мою программу из первого поста.

Создаем класс:

using System;
using System.Runtime.InteropServices;


namespace WindowControl
{
    public class TestStruct
    {
        private readonly IntPtr _intPtr;

        public TestStruct(IntPtr pointer)
        {
            _intPtr = pointer;
        }



        public int P1 {
            get { return Marshal.ReadInt32(_intPtr); }
            set { Marshal.WriteInt32(_intPtr, 0, value); }
        }
        public int P2
        {
            get { return Marshal.ReadInt32(_intPtr, 4); }
            set { Marshal.WriteInt32(_intPtr, 4, value); }
        }
        public double P3
        {
            get { return BitConverter.Int64BitsToDouble(Marshal.ReadInt64(_intPtr, 8)); }
            set { Marshal.WriteInt64(_intPtr, 8, BitConverter.DoubleToInt64Bits(value)); }
        }
        public double P4
        {
            get { return BitConverter.Int64BitsToDouble(Marshal.ReadInt64(_intPtr, 16)); }
            set { Marshal.WriteInt64(_intPtr, 16, BitConverter.DoubleToInt64Bits(value)); }
        }
    }
}

Для получения и перезаписи значений используется маршалинг, никакого unsafe в чистом виде. Смещения в байтах выставляем согласно тому, какие они будут в оригинальной структуре из MQL4(не забываем, что в том языке выравнивание структур не производится).

Класс TestStruct представляет из себя обертку над некой областью неуправляемой памяти и не больше.

Вот так перезаписываем значения:

using System;


namespace WindowControl
{
    public static class ExportFunctions
    {
        [System.Reflection.Obfuscation(Feature = "DllExport")]
        public static void CallMe(IntPtr pointer)
        {
            TestStruct ts = new TestStruct(pointer);
            ts.P1 = 10;
            ts.P2 = 333;
            ts.P3 = 5.22;
            ts.P4 = 784.214;
        }
    }
}

Все, вызываем скрипт из второго листинга. Терминал печатает те значения, которые мы записали в библиотеке. У меня все работает.