Unresolved import function call in dll

 

Почему вылазить такое сообщение?

Есть эксперт:

//+------------------------------------------------------------------+
//|                                                         Test.mq4 |
//|                                                              hoz |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "hoz"
#property link      ""
#property version   "1.00"
#property strict
#import  "TestDll.dll"
   int GetSum();
#import
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
     int res = GetSum();
     Print("res = ", res);
  }
//+------------------------------------------------------------------+

И dll:

using System;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
namespace TestDll
{
    public class SumTwoInt
    {
        [DllExport("GetSum", CallingConvention = CallingConvention.StdCall)]
        public int GetSum()
        {
            int firstNum = 2;
            int secondNum = 5;

            return firstNum + secondNum;
        }
    }
}

Ни в тестере, и в реале терминал не может "увидеть"
 метод сложения 2 чисел. Вылазил следующее:

2015.05.16 11:32:51.880 EURUSD,H1: 1 tick events (1625 bars, 1814843 bar states) processed within 15 ms (total time 4960 ms)
2015.05.16 11:32:51.880 2015.03.23 00:00  Testing pass stopped due to a critical error in the EA
2015.05.16 11:32:51.879 2015.03.23 00:00  unresolved import function call
2015.05.16 11:32:51.879 2015.03.23 00:00  Cannot find 'GetSum' in 'TestDll.dll'
2015.05.16 11:32:51.875 Test test started
2015.05.16 11:32:46.921 TestGenerator: current spread 11 used

Что не так?

При написании пользовался статьёй.

Эксперт и саму dll я прикрепил к посту.

Файлы:
testdll.zip  4 kb
test.mq4  2 kb
 
using RGiesecke.DllExport;

Последний раз, когда пробовал добавлять эту сборку в проект, то она не работала, да и, судя по постам в инете, у всех было то же самое, а автор перестал ее поддерживать.

Также, надеюсь, вы понимаете, что эта библиотека - это хак, то есть, человек воспользовался недокументированными возможностями Microsoft для того, чтобы после компиляции ручками подправить файл IL.

Я удивлен, что она вообще заработала у вас, это случайность ... 

Сообщение вероятней всего выладит потому что Microsoft могло немного изменить формать IL файлов, а библиотека Роберта пытается найти несуществующий фрагмент и подправить его, в результате не находит его и получается, что функции, которые вы пытаетесь сделать видимыми в Native Code, в частности в МТ, там попросту отсутствуют, МТ их не видит.

Теперь у вас два выхода - общаться с автором чтобы понять что не так или перечитать эти статьи и попытаться проверить корректность изменений в вашем IL файле самому :

http://habrahabr.ru/sandbox/30366/

http://habrahabr.ru/post/137300/

А вот то, как сделать это по-человечески :

http://habrahabr.ru/post/84076/

 
Ничего себе. Судя по всему нативной поддержи dll нет, хотя тут и сказано, что типа возможность имеется. И то, что должно быть реализуемо разработчиком, нужно лопатить трейдеру? Жесть...
 
hoz:
Ничего себе. Судя по всему нативной поддержи dll нет, хотя тут и сказано, что типа возможность имеется. И то, что должно быть реализуемо разработчиком, нужно лопатить трейдеру? Жесть...

Нет, вы меня не поняли :)

Поддержка DLL в МТ есть, с этим никто не спорит, но есть разные виды DLL :

1. созданные в unmanaged code, like native C, будут без проблем подключаться в МТ и работать нормально, вот рабочий пример - https://www.mql5.com/ru/articles/18

2. созданные в managed code, like .NET, при компиляции НЕ включают в себя функцию экспорта функций, .NET экспортирует функции через DEF файлы, а МТ пытается найти в DLL секцию экспорта

Чтобы понять разницу, возьмите любую DLL созданную с помощью C++ и откройте ее в этой программке - http://www.nirsoft.net/utils/dll_export_viewer.html - увидите все экспортируемые функции и они будут доступны в МТ.

Теперь в этой же программке попытайтесь открыть вашу DLL из .NET и вы не увидите там ни одной функции потому что при компиляции C# просто не добавляет нужную секцию в DLL. Библиотека R. Giesecke была создана для того, чтобы грубо вклиниваться в процесс компиляции DLL и добавлять сгенеренную руками секцию с именами всех экспортируемых функций, но это ХАК, при малейшем изменении формата данных эта библиотека перестанет работать, что вероятно и случилось в вашем случае, кстати, она и от языка компилятора зависит, вроде бы в русской VStudio библиотека также не работала потому что какая-то другая секция занимала чуть больше места и данные об экспортируемых функциях записывались не в то место :)

Чтобы сделать методы C# видимыми в МТ, то есть в native code, надо воспользоваться одним из методов перечисленных здесь - https://www.mql5.com/ru/articles/18 - мне больше нравится IJW, или, если лень писать обертку, то можно сразу писать DLL на С++.

 

artemiusgreat, что Вы имеете в виду под IJW ?

 В приведённой выше статье речь идёт о dll написанных на С++. Мне удобнее писать на Шарпе. Так что обёртку писать будет не лень. Знать бы как..

 
hoz:

artemiusgreat, что Вы имеете в виду под IJW ?

 В приведённой выше статье речь идёт о dll написанных на С++. Мне удобнее писать на Шарпе. Так что обёртку писать будет не лень. Знать бы как..

Под IJW подразумевается It Just Works, он упоминается в статье от Investeo выше.

Два хороших примера реализации :

http://www.codeproject.com/Tips/695387/Calling-Csharp-NET-methods-from-unmanaged-C-Cplusp

http://pragmateek.com/using-c-from-native-c-with-the-help-of-ccli-v2/

Несколько полезных ссылок по теме : 

http://stackoverflow.com/questions/2719985/calling-managed-c-sharp-functions-from-unmanaged-c

http://bit.ly/1H92a2G

Вот так реализовал у себя :

http://snag.gy/DJvQS.jpg

1. проект Libs - managed code C# - основная логика здесь

2. проект Links - unmanaged C++ CLI - здесь обертки для методов из C#

Остальные проекты - дополнительные, Presentation - графическая оболочка WinForms для визуального тестирования, Console - имитация подключения DLL из native code, для отладки

Как видно на скрине в проекте Links есть файлик Common.h - в проект включается сборка Libs, и в самом файле добавляются необходимые namespaces, теперь из Links можно вызывать методы от Libs и они будут видимы в МТ.

Например, в C# есть метод для получения массива структур, типа CopyRates :

public byte[] GetQuotesBytes(string symbol)
{
    return GetQuotes(symbol).Points.SelectMany(x => Conversion.BytesFrom<Point>(x)).ToArray(); // get List<Point> and convert it to bytes array
}

Для него в С++ создана обертка :

#define ECV extern "C" __declspec(dllexport) void __cdecl

ECV GetQuotes(char * name, char * symbol, int * bytes, int size, int count)
{
        try
        {
                array<Byte> ^ data = Quotes::GetInstance(gcnew String(name))->GetQuotesBytes(gcnew String(symbol));
                Marshal::Copy(data, int(0), IntPtr(bytes), size * count); // copy bytes array to unmanaged memory so that MT could get it
        }
        catch (Exception ^ e)
        {
                Messages::Log(e->Message + e->StackTrace, DEBUG);
        }
}

К сожалению, типы данных в управляемом и неуправляемом кодах не совпадают, а потому приходится делать Marshal.Copy при конвертации данных C# <-> C++, думал о более простых вариантах передачи данных здесь, но пока все кажется костыльным - https://www.mql5.com/ru/forum/58652

Чтобы все 4 проекта билдились в одну DLL билд делаю с помощью скрипта во вложении, студию дольше настраивать будет.

Файлы:
builddll.zip  1 kb
 

Я так понимаю, пишется библиотека на С#, потом к ней обёртка на С++, а потом всё это хозяйство вместе компилится в одну dll, так? Но я видел, там ещё хедер используется. Инфы много...

Думаю, либо это всё переварить, либо пойти куда-нить, где платформа напрямую поддерживает Шарпея. Как-то сложно всё это лопатить одним махом...

Особенно, если это ещё лишь базовые моменты.