Pull to refresh

Делаем библиотеку написанную на .Net понятной для Unmanaged кода

Reading time3 min
Views10K
Пол года проработав в компании, которая занимается программированием на MQL под Meta Trader столкнулся с таким заказом: клиенту нужно что бы программа была написана на C# или VB.Net.

Задача была в том, что бы написать программу на C# и dll на том же языке, которая связывает приложение с торговым советником на MQL. С одной стороны мне это на руку, так как C# изучаю больше года, с другой — стало непонятно, а как же это делается и вообще возможно ли это?
image

Ни для кого не секрет, что библиотека, написанная на C# не имеет в своем коде раздела для экспорта, и собственно передать название функции не является возможным. Пару часов поисков в интернете таки дали мне понять, что решение существует, и состоит оно в следующем:
  • Нужно декомпилировать библиотеку при помощи ILDASM, получив при этом IL-код
  • Изменить код так, что бы функции стали экспортируемыми
  • Заново собрать при помощи ILASM

Про IL что-то там слышал, но в глаза ни разу не видал сие чудо. Что бы вам не пришлось искать литературу, которой по данному вопросу не так и много, опишу всё шаг за шагом. В результате у нас получится библиотека, которая отлично запускается из любой программы.

Итак приступим:
Первым делом создадим обычную библиотеку, в которой будет 2 метода, где первый выводит на экран всем любимое «Hello, World!», второй возвращает сумму двух чисел.

Названия функций желательно выбрать такими, которые потом будет легко найти.
Собственно вот как выглядит код нашей библиотеки:

using System;
using System.Windows.Forms;

namespace Test
{
    public class Class1
    {
        public static void Message_Export(String message)
        {
            MessageBox.Show(message);
        }

        public static Double Sum_Export(Double a, Double b)
        {
            return a + b;
        }
    }
}


Обратите внимание «Export» в названии функции нужно лишь для более удобного поиска в файле, что не является обязательным. модификатор public можно как указывать, так и нет, для экспортируемых функций это не играет большой роли, однако методы обязательно должны быть статическими.

Далее компилируем эту библиотеку, и запускаем декомпилятор при помощи командной строки Visual Studio
Пуск > Все программы > Microsoft Visual Studio 2010 > Visual Studio Tools > Командная строка Visual Studio (2010). Пишем ildasm и нажимаем Enter.
image

В появившейся программе нажимаем Файл > Открыть и указываем путь к нашей библиотеке
image
и получаем дерево классов и методов нашей библиотеки

Далее Файл > Дамп, все настройки оставляем по умолчанию и сохраняем наш файл с названием, например Test.il на диск, где файл легко будет найти, у меня это D:\
image

С декомпиляцией закончили, по сути ничего тяжелого. Следующим делом открываем созданный файл Test.il при помощи любого текстового редактора и видим код, который на первый взгляд кажется совсем непонятным. Ничего сложного в нем нет, но оно нам особо и не нужно знать что там и где.
Для начала находим запись ".corflags 0x00000001" которая означает, что файл содержит только il-код, и компилятор будет попросту игнорировать все попытки экспорта функций, изменяем ее на ".corflags 0x00000002"

В этом же разделе файла, сразу после записи .corflags нам необходимо выдилить память для двух наших функций.

.vtfixup [1] int32 fromunmanaged at VT_01
.vtfixup [1] int32 fromunmanaged at VT_02
.data VT_01 = int32(0)
.data VT_02 = int32(0)


последним этапом в редактировании кода будет сам экспорт необходимых фунций
находим первую функцию

.method public hidebysig instance void 
          Message_Export(string message) cil managed
  {
    // Размер кода:       9 (0x9)


комментарии можно удалять, но это не обязательно, т.к. компилятор не добавит их в dll.
В начале функции пишем запись такого вида:

.vtentry 1 : 1
.export [1] as Message


собственно под именем Message и будет вызываться эта функция из библиотеки.

в начало второй

.method public hidebysig instance float64 
          Sum_Export(float64 a,
                     float64 b) cil managed
  {
    // Размер кода:       9 (0x9)


вставляем
.vtentry 1 : 2
.export [2] as Sum

соответственно.

Всё что нам осталось, это собрать нашу библиотеку. В командной строке Visual Studio пишем следующее:
ilasm /OUT:D:\Test.dll D:\Test.il /dll

Если получили сообщение Operation Completed Sucefully, значит всё сделано правильно и библиотека скомпилировалась.
image
Tags:
Hubs:
Total votes 43: ↑27 and ↓16+11
Comments40

Articles