Развертывание управляемого и неуправляемого кода в одной сборке
Воскресенье, 4 февраля 2007 г.
.NET разработчики любят развертывание XCOPY. И они любят отдельные компоненты сборки. По крайней мере, я всегда чувствую себя немного неловко, если мне нужно использовать какой-то компонент и мне нужно запомнить список файлов, которые также должны быть включены в основную сборку этого компонента. Поэтому, когда мне недавно пришлось разработать компонент управляемого кода и дополнить его некоторым неуправляемым кодом из DLL C (спасибо Маркусу Хигу за помощь в этом!), Я подумал о том, как упростить развертывание двух DLL. , Если бы это были всего две сборки, я бы использовал ILmerge, чтобы собрать их в один файл. Но это не работает для компонентов смешанного кода с управляемыми и неуправляемыми DLL.
Итак, вот что я придумал для решения:
Я включаю все библиотеки DLL, которые хочу развернуть, с основной сборкой моего компонента в качестве встроенных ресурсов.
Затем я установил конструктор класса для извлечения этих DLL, как показано ниже. Класс ctor вызывается только один раз в каждом AppDomain, поэтому я думаю, что это незначительные накладные расходы.
namespace MyLib
{
public class MyClass
{
static MyClass()
{
ResourceExtractor.ExtractResourceToFile("MyLib.ManagedService.dll", "managedservice.dll");
ResourceExtractor.ExtractResourceToFile("MyLib.UnmanagedService.dll", "unmanagedservice.dll");
}
...
В этом примере я включил две библиотеки DLL в качестве ресурсов, одну - библиотеку неуправляемого кода, а другую - библиотеку управляемого кода (только для демонстрационных целей), чтобы показать, как этот метод работает для обоих типов кода.
Код для извлечения DLL-файлов в собственные файлы прост:
public static class ResourceExtractor
{
public static void ExtractResourceToFile(string resourceName, string filename)
{
if (!System.IO.File.Exists(filename))
using (System.IO.Stream s = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Create))
{
byte[] b = new byte[s.Length];
s.Read(b, 0, b.Length);
fs.Write(b, 0, b.Length);
}
}
}
Работа с подобранной сборкой управляемого кода аналогична обычной - почти. Вы ссылаетесь на него (здесь: ManagedService.dll) в основном проекте вашего компонента (здесь: MyLib), но для свойства Copy Local установлено значение false. Кроме того, вы связываете сборку как существующий элемент и устанавливаете для действия сборки значение «Встроенный ресурс».
Для неуправляемого кода (здесь: UnmanagedService.dll) вы просто ссылаетесь в DLL как на существующий элемент и устанавливаете для действия сборки значение «Встроенный ресурс». Для доступа к его функциям используйте атрибут DllImport как обычно, например,
[DllImport("unmanagedservice.dll")] public extern static int Add(int a, int b);
Вот и все! Как только вы создаете первый экземпляр класса со статическим ctor, встроенные библиотеки DLL извлекаются в свои собственные файлы и готовы к использованию, как если бы вы развернули их как отдельные файлы. Пока у вас есть права на запись для каталога выполнения, это должно работать для вас нормально. По крайней мере, для прототипного кода, я думаю, этот способ развертывания одной сборки весьма удобен.
Наслаждайтесь!
http://weblogs.asp.net/ralfw/archive/2007/02/04/single-assembly-deployment-of-managed-and-unmanaged-code.aspx