Pull to refresh

Создание динамически загружаемой DLL библиотеки на C#

Задача

Не так давно у нас появилась необходимость создать расширение для одной программы на языке C# с использованием WPF. Расширение представляет собой динамически загружаемую dll библиотеку, о создании которой и пойдет речь в данной статье.

Нам не удалось найти стандартное средство в языке C# для создание динамической dll, по этому были рассмотрены обходные методы:

Первый способ – это создание динамически загружаемой dll на managed C++, из которой, производилось обращение к сборке на C#

Второй способ – создание сборки на языке C# и путем декомпиляции в IL код и обратно, приведение этой библиотеки к нужному виду.

О втором способе расскажу подробнее:

Создание динамической dll путем пере компиляции в il

Для реализации нам потребуются две утилиты ilasm и ildasm, эти утилиты должны поставляться вместе со средой разработки, у меня они лежали в этих папках:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\

C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools

Для удобства я добавил эти пути в Path, потому что придется часто пользоваться этими утилитами в командной строке.

Далее необходимо создать библиотеку классов на языке C#. Функции которые необходимо экспортировать, должны быть публичными и статическими, и находиться в публичном классе. В качестве параметров и возвращаемого значения можно использовать простые типы, такие как string, int.

Пример кода:
public class TestExportClass
{
public static void Run()
{
MessageBox.Show("Привет из C#");
}
}


Скомпилируем проект, получаем dll библиотеку. (у меня TestDll.dll)

Теперь необходимо преобразовать dll библиотеку в il код. Для этого нужно запустить ildasm в командной строке со следующими параметрами

ildasm TestDll.dll /OUT:TestDll.il


Далее необходимо проделать некоторые манипуляции с получившимся il кодом.

Во-первых, меняем флаг

.corflags 0×00000001


на

.corflags 0×00000002


Во-вторых, над началом описания классов (обычно эта область отделена комментарием CLASS MEMBERS DECLARATION) добавляем код:

.vtfixup [1] int32 fromunmanaged at VT_01

.data VT_01 = int32(0)


В-третьих, в методе который необходимо сделать экспортируемым добавляем код:

.vtentry 1 : 1

.export [1] as Run


Здесь Run – это название метода, по которому его будет вызывать сборка, написанная на неуправляемом коде.

Теперь необходимо скомпилировать dll библиотку, для этого воспользуемся утилитой ilasm, с параметрами:

ilasm TestDll.il /OUT:TestDll.dll /DLL


Все после этого dll можно использовать как обычную динамически загружаемую dll библиотеку.

Динамическая dll + WPF


Если вы планируете создавать расширение с использованием технологий, требующих, чтобы приложение работало в STA потоке (Например WPF), то необходимо учесть, что поток в котором будет выполняться расширение наследуется от сборки запустившей библиотеку, а значит может быть не в режиме STA.

Для того чтобы обойти эту проблему было решено в расширении создать STA поток и в нем запускать окна на WPF.

Вот так можно модернизировать код для запуска WPF окна:

public static void Run()
{
Thread WPFThread = new Thread(OpenWTPWindow);
WPFThread.ApartmentState = ApartmentState.STA;
WPFThread.Start();
WPFThread.Join();
}

public static void OpenWTPWindow()
{
System.Windows.Window WPFWindow = new System.Windows.Window();
WPFWindow.ShowDialog();
}


Обратите внимание что окно запускается не с помощью функции Show() а ShowDialog(), функция Show() работает некорректно, при использовании её не в основном потоке.

Заключение


Такой метод зарекомендовал себя при разработки расширений для различных программ которые требуют, в качестве подключаемого модуля динамически загружаемую DLL библиотеку.

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

Ссылки по теме


Хорошая статья. Если у вас остались еще какие то вопросы по созданию динамической dll, рекомендую обратиться к ней.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.