Экспорт функций из Net dll | C# DLLExport | .NET Framework в Metatrader

Категория: Metatrader
Опубликовано 22.09.2012 00:15

Изначально статья была размещена на форуме, решил скопировать сюда, на всякий.

Решил написать небольшой мануал по созданию dll для Metatrader на платформе .NET Framework. Также он пригодится тем программистам, кому нужно сделать вызов из неуправляемого кода в управляемый в любых других программах. Вам мануал может сэкономить кучу времени на эксперименты, попытки запустить выложенные в интернете решения. К сожалению ничего готового и работающего в сети я не нашел. То, что нашел, не смог запустить, видимо не хватило опыта. Например готовый шаблон Unmanaged Exports by Robert Giesecke не захотел компилироваться еще на этапе, когда был только добавлен в решение. Мануал на кодепроекте почему-то обрывал дизассемблированный IL-файл. Можно конечно все сделать через дллку на C++/CLI, но хотелось обойтись без промежуточных dll. Есть обфускатор, который обладает такой функцией, но покупать лицензию за 5килорублей ради одной опции не вижу смысла. Тем более что все оказалось в итоге совсем не сложно.

Итак. Если вы решили написать dll на C# и нужно вызвать ее из unmanaged программы, коей является тот же Metatrader, то столкнетесь с большой проблемой. Которая заключается в том, что managed код изначально плохо совместим с unmanaged средой. И если о вызове неуправляемого код управляемым можно почитать на MSDN (P/Invoke), то об обратном вызове как то умалчивается. Его можно обыграть через COM, либо через враппер на C++. Но для того, чтобы вызывать непосредственно, нужно, чтобы в вызываемой сборке присутствовала таблица экспорта функций. А создать ее с помощью C# нет возможности. Но можно дизассемблировать полученную DLL, добавить таблицу и снова собрать сборку. Минус - не получится использовать strong name.

Чтобы автоматизировать и упростить процесс экспортирования функций, я написал консольную программу ExportDll, качаем.

Буду описывать пошагово.
Создаем в Visual Studio библиотеку классов C# с названием например Test. Если собираемся передавать в длл указатели, то открываем свойства проекта, вкладка Построение и добавляем галочку Разрешить небезопасный код.

Добавляем код:

using System;
using System.Collections.Generic;
using System.Text;
 
namespace Test
{
	public class Class1
	{
		[System.Reflection.Obfuscation(Feature = "DllExport")]
		public static void Test(int i)
		{
			System.Windows.Forms.MessageBox.Show(i.ToString());
		}
	}
}

 

То есть экспортируемая функция должна быть public static и помечена атрибутом DllExport, как показано в коде. Функций может быть несколько, каждую надо пометить.
Далее скачиваем архив с ExportDll, распаковываем. В файле Params.set должны быть указаны правильные пути для ilasm и ildasm. По умолчанию я выставил свои пути (Net Framework 4 и Visual Studio 2010).
Далее снова открываем свойств проекта, вкладка События построения. В поле Командная строка события после построения вписываем:

"c:\Program Files\ExportDll\ExportDll.exe" "$(TargetPath)"

где "c:\Program Files\ExportDll\ExportDll.exe" путь к распакованной утилите.
Нажимаем сохранить, далее Строим решение (кнопка F7).

Полученный результат нужно проверить. В этом поможет утилита Dependency Walker. Скачиваем ее, распаковываем, запускаем, кидаем в нее полученную длл и смотрим:

Как видно на скриншоте, все работает. Теперь дллка подключается к советнику стандартным способом через import и функция Test корректно вызывается. Можно проверить:

#import "Test.dll"
	void Test(int);
#import
void start()
{
	Test(123456);
}

 

Комментарии   

+2 # GB 02.06.2014 18:47
отлично. очень годный материал. так не охото было перечитывать msdn...
Ответить | Ответить с цитатой | Цитировать
0 # Dan 22.08.2014 20:10
Молодец.
Насколько я понимаю это приложение пересобирает сборку , с указанием индексов к методу.
Ответить | Ответить с цитатой | Цитировать
0 # Jonxxx 22.08.2014 21:56
Да, именно так.
Ответить | Ответить с цитатой | Цитировать
0 # Andrey 11.09.2014 18:42
Спасибо за проделанную работу и предоставленную по ней информацию!
Действительно на изучение этого вопроса убил кучу времени, а толковой информации так и не нашел...За исключением этой :-) .
Ответить | Ответить с цитатой | Цитировать
0 # tobin 04.11.2014 20:42
подскажите пожалуйста, как быть со строками
Ответить | Ответить с цитатой | Цитировать
0 # Jonxxx 05.11.2014 19:49
Цитирую tobin:
подскажите пожалуйста, как быть со строками

В самом верху
http://jonxxx.me/13-metatrader/26-metatrader-i-dll-rabotaem-so-strokami
Ответить | Ответить с цитатой | Цитировать
0 # tobin 19.11.2014 19:31
Спасибо, разобрался заработало ))
Вам случайно не показывал MT4 unhandled exception 0xE0434F4D? Поиск по гуглу не дал результатов.
Ответить | Ответить с цитатой | Цитировать
0 # Jonxxx 19.11.2014 19:41
Значит исключение в вашей библиотеке выбрасывает.
Ответить | Ответить с цитатой | Цитировать
0 # Tora 25.12.2014 15:45
и нифига не работает

using System.Reflection;
using System.Windows.Forms;

namespace total {
public class sovk {

[Obfuscation(Feature = "DllExport")]
public static void total_(int i) {
MessageBox.Show(i.ToString());
}

ExportDll.bat
ExportDll.exe "d:\total\bin\total.dll"
pause

Params.set
ilasmpath="c:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe"
ildasmpath="c:\Program Files (x86)\Microsoft SDKs\Windows\v8 .0A\bin\NETFX 4.0 Tools\ildasm.ex e"
Ответить | Ответить с цитатой | Цитировать
0 # Jonxxx 25.12.2014 20:32
dll нормально пересобралась? метод попал в таблицу экспорта?
Ответить | Ответить с цитатой | Цитировать
0 # Tora 25.12.2014 20:42
собралась и дальше студия пишет в окне вывода, что ildasm не найден. Путь правильный, кавычки пробовал поставить и убрать
Ответить | Ответить с цитатой | Цитировать
0 # Jonxxx 25.12.2014 21:40
У меня без кавычек работало. Пробуйте, скопипастив этот путь в cmd, запустить дизассемблер оттуда.
Ответить | Ответить с цитатой | Цитировать
0 # Tora 25.12.2014 22:10
запускается
Ответить | Ответить с цитатой | Цитировать
0 # diushych 04.03.2015 14:48
спасибо ;)

скажите, а файлик .def нужно приделывать?

пытаюсь собрать, в студии, сама либа компилиться без вопросов, с ExportDll выдает ошибку -2147024703, в 16-м = 0х800700С1

в консоли тоже
D:\programs\ExportDll>ExportDll.exe ChartEventLib.dll
D:\programs\ExportDll>echo Exit Code is %errorlevel%
Exit Code is -2147024703

или 0х800700С1, вот что бы это значило?
Ответить | Ответить с цитатой | Цитировать
0 # diushych 04.03.2015 16:02
вопрос снят, проблема была в конфигурации системы. На другой собрал свою длл-льку с полпинка ;)))

аффтару респект
Ответить | Ответить с цитатой | Цитировать
0 # diushych 06.03.2015 14:29
Вот что еще обнаружил, длл работает исправно в той системе где собиралась. На других компах не пашет, ошибка - пресловутая 0xE0434F4D
C Unmanaged Exports by Robert Giesecke та же трабла сейчас у многих, причем и на родном компе и на "посторонних"
Ответить | Ответить с цитатой | Цитировать
0 # Jonxxx 06.03.2015 17:53
Очень странно. Я когда писал дллки для мт4, отправлял их заказчикам и никогда проблем не было, лишь бы нужная версия дотнета стояла.
Ответить | Ответить с цитатой | Цитировать
0 # Vladimir 08.03.2015 19:46
в МТ5, вне зависимости от параметров в VS и параметров Params.set выдает ошибку:
****.dll is not 64-bit version

Params.set пробовал:
1.
ilasmpath=c:\Windows\Microsoft.NET\Framework64\v4.0.30319\ilasm.exe
ildasmpath=c:\Program Files (x86)\Microsoft SDKs\Windows\v8 .0A\bin\NETFX 4.0 Tools\x64\ildasm.exe
2.
ilasmpath=c:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe
ildasmpath=c:\Program Files (x86)\Microsoft SDKs\Windows\v8 .0A\bin\NETFX 4.0 Tools\ildasm.ex e
3.
ilasmpath=c:\Windows\Microsoft.NET\Framework64\v4.0.30319\ilasm.exe
ildasmpath=c:\Program Files (x86)\Microsoft SDKs\Windows\v8 .0A\bin\NETFX 4.0 Tools\ildasm.ex e
Ответить | Ответить с цитатой | Цитировать
0 # wmysterio 08.07.2015 21:14
При импорте функций пишет ошибку "Не удается открыть файл библиотека типов". Сделал всё в точности как в статье. При компиляции C# никаких ошибок не наблюдалось.
Ответить | Ответить с цитатой | Цитировать
0 # Jonxxx 08.07.2015 21:46
Проверили через Dependency Walker, точно функции импортированы корректно?
Ответить | Ответить с цитатой | Цитировать
0 # Gleb 25.07.2015 19:54
9009 выдаёт :sad:
Ответить | Ответить с цитатой | Цитировать
0 # Gleb 25.07.2015 19:52
Ошибка 1 выход из команды ""C:\Program Files\ExportDll " "c:\users\глеб\ documents\visua l studio 2013\Projects\S hare\Share\bin\ Release\Share.d ll"" с кодом 9009. Share

печаль, а так хотелось :cry:
Ответить | Ответить с цитатой | Цитировать
0 # atlet65 28.09.2015 09:48
Привет. Смотрю и этот проект погиб. У меня ничего не выходит. Ни одна dll не загружается и с ваших примеров и других. Одно сообщение всегда dll не для 64-х разрядных систем. Может кто подскажет в чем проблема и как создать dll способную подключиться. Спасибо.
Ответить | Ответить с цитатой | Цитировать
0 # Jonxxx 01.10.2015 01:05
Я к сожалению вряд ли смогу помочь, так как давно уже забил на форекс, а кроме метатрейдера нигде больше такое извращение делать не приходилось.
Ответить | Ответить с цитатой | Цитировать
0 # Александр 11.10.2015 15:15
Скорее всего при компиляции 64 битного приложения вы не используете флаг /pe64, поэтому и DLL компилируется в 32 битном режиме. Поэтому исправить данную ошибку.
Ответить | Ответить с цитатой | Цитировать
0 # Александр 11.10.2015 13:30
Можешь выложить исходники ExportDLL, чтобы можно было разобраться с x64 режимом. В x89 режиме все хорошо работает, а вот 64-битные DLL не корректно создаются и поэтому не загружаются. Может быть где-то есть ошибка, хочется разобраться. А ты этой темой уже не занимаешься.
Ответить | Ответить с цитатой | Цитировать
+1 # Jonxxx 12.10.2015 00:01
Завтра вечером на github выложу.
Ответить | Ответить с цитатой | Цитировать
0 # Александр 13.10.2015 10:44
Да это было бы здорово.
Ответить | Ответить с цитатой | Цитировать
0 # Jonxxx 13.10.2015 23:28
https://github.com/Jonxxx/ExportDll
Программа простейшая, я ее писал еще когда только начинал. Если несложно, после исправления сделай pr, я выложу в пост исправленную версию.
Ответить | Ответить с цитатой | Цитировать
0 # Александр 14.10.2015 12:13
Я начал писать свой вариант. Как только сделаю, выложу :D
Зачем ты пишешь вот это?
fs.WriteByte(0xEF);
fs.WriteByte(0xBB);
fs.WriteByte(0xBF);
Ответить | Ответить с цитатой | Цитировать
0 # Jonxxx 14.10.2015 23:15
Не помню, это ж было много лет назад.
Ответить | Ответить с цитатой | Цитировать
0 # Александр 16.10.2015 23:41
В вашем варианте нужно было только добавить ключ компиляции /x64 и в 64 битном режиме не заменять .corflags. Я несколько доработал программу, добавив дополнительные возможности.
Ответить | Ответить с цитатой | Цитировать
+1 # Александр 16.10.2015 23:39
Цитирую Jonxxx:
https://github.com/Jonxxx/ExportDll
Программа простейшая, я ее писал еще когда только начинал. Если несложно, после исправления сделай pr, я выложу в пост исправленную версию.

Спасибо вам за информацию. Вот выкладываю свой вариант. _https://yadi.sk/d/E1x2KDeLjniVB
Теперь должно работать 32 и 64 битная версия.
Ответить | Ответить с цитатой | Цитировать
+1 # Александр 16.10.2015 23:48
Пользоваться так же как описано в статье. Для компиляции в 64 битном режиме или режиме отладки нужно задать ключи: /x64 /debug /optimize
Ответить | Ответить с цитатой | Цитировать
0 # Дмитрий 16.03.2016 17:03
Доброго времени суток, Александр. А Вы не могли бы выложить исходники уже своей исправленной версии или сделать вывод информации в ней? Дело в том, что я делаю простой проект на .net 4.5, тип сборки x64, подключаю пакет SteamKit2 и свои классы для работы - и ExportDll перестает отзываться. То есть я запускаю файл, передаю все параметры - выполнение висит, ничего не происходит. Только в папке с dll появляются декомпилированн ые файлы и все.
Ответить | Ответить с цитатой | Цитировать
-1 # Alex 19.10.2015 11:45
Александр, спасибо вам за ваш вариант, но не могли бы вы немного пояснить про 64 битную сборку, для тех кто на вы с VS):
Ответить | Ответить с цитатой | Цитировать
0 # Александр 19.10.2015 12:20
Каких пояснений вы хотите? Все то же самое, что и с 32 битной сборкой. Сначала компилируете проект в 64 битном режиме (в настройках=>кон ечная платформа=>x64) . Затем запускаете ExportDLL с ключом /x64. Все должно работать.
Я использую события построения в VS2012 => командная строка события после построения =>
"ExportDLL.exe" "$(TargetPath)" /$(Configuratio nName) /$(PlatformName)
При этом путь до ExportDLL.exe нужно прописать в Path или кинуть этот файл в системную папку windows.
Ответить | Ответить с цитатой | Цитировать
0 # Alex 19.10.2015 12:45
Александр, спасибо вам за подробный и развернутой ответ! Буду пробовать...
Ответить | Ответить с цитатой | Цитировать
0 # Александр 19.10.2015 12:51
В файлике params.set указываются пути до ilasm и ildasm. Эти пути должны совпадать с той версией net, которую вы используете при компиляции.
Ответить | Ответить с цитатой | Цитировать
0 # Alex 19.10.2015 12:59
Александр, я использую 2010 VS, просто я плохо в ней ориентируюсь и просто методом тыка пытаюсь найти что такое ключ /х64, а главное где писать)) ну как говориться если долго мучиться... :lol: Еще раз спасибо..
Ответить | Ответить с цитатой | Цитировать
0 # Alex 19.10.2015 13:12
Все получилось! х64 не дописал в событие после построения и поэтому компилировась как 32 битная...
Ответить | Ответить с цитатой | Цитировать
0 # Maximum13 08.03.2017 17:49
А можно получить исходники ExportDLL?
Ведь ilasm по умолчанию собирает 32-битный dll-файл, а мне нужно указывать, чтоб собирал 64-битный при помощи флага /X64.
Ответить | Ответить с цитатой | Цитировать