
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.207] |
![]() |
|
Сообщ.
#1
,
|
|
|
Столкнулся с проблемой.
Библиотеки написаны на c#. Первую библиотеку, библиотеку1, подключаю из c++ проекта (run-time - это когда запущен этот проект). Охота из dll в run-time (т.е. когда ее используют) подключить другую библиотеку, библиотеку2, (тоже c#) и поюзать ее методы. При этом ставится еще одно условие! Что бы не останавливая run-time проекта пересобирать библиотеку2. Как это сделать? |
Сообщ.
#2
,
|
|
|
Цитата Охота из dll в run-time (т.е. когда ее используют) подключить другую библиотеку, библиотеку2, (тоже c#) и поюзать ее методы. В .NET лучше ссылку добавить в reference сборки, чтобы подгрузилась при загрузке. Зачем тебе в рантайм? Память экономишь? Забудь, та же ХР скажем все равно это закеширует в каком-нить Prefetch и ничего ты не выиграешь. LoadLibrary это вчерашний день. Цитата При этом ставится еще одно условие! Что бы не останавливая run-time проекта пересобирать библиотеку2. Как это сделать? Тут я тебя не понял |
Сообщ.
#3
,
|
|
|
Как раз хочу обойтись без reference.
К примеру, я передаю методу из dll имя библиотеки, которую надо загрузить и выполнить метод, имя которого я знаю. При этом имя может быть произвольное, да и в следующем вызове, та же самая библиотека может быть пересобрана (между вызовами). А LoadLibrary - в c# нету. Или я ошибаюсь? |
Сообщ.
#4
,
|
|
|
Цитата DarkKo, 15.09.03, 11:06:44 Как раз хочу обойтись без reference. К примеру, я передаю методу из dll имя библиотеки, которую надо загрузить и выполнить метод, имя которого я знаю. Такие вещи делаются через рефлекшн. смотри Activator. Загружаешь нужный тебе тип и вызываешь нужный метод (Invoke) Цитата При этом имя может быть произвольное, да и в следующем вызове, та же самая библиотека может быть пересобрана (между вызовами). А LoadLibrary - в c# нету. Или я ошибаюсь? Assembly.LoadFrom или Assembly.LoadWithPartialName |
Сообщ.
#5
,
|
|
|
Загрузить библиотеку получилось!
Спасибо! ![]() ![]() <br>Assembly SecondScriptAssembly;<br>SecondScriptAssembly = Assembly.LoadFrom("...\\dinamo.dll");<br>Object fromdll = SecondScriptAssembly.CreateInstance("dinamo.PrintMessage");<br>MethodInfo Method;<br>Method = SecondScriptAssembly.GetTypes()[0].GetMethod("Message");<br>Object [] paramasa = new object[1];<br>paramasa[0] = "Importede string\n";<br>Method.Invoke(fromdll,paramasa);<br> А вот как теперь ее выгрузить, что бы пересобрать, например? Т.е. что бы эта dinamo.dll освободилась! |
Сообщ.
#6
,
|
|
|
Цитата DarkKo, 15.09.03, 12:58:56 Загрузить библиотеку получилось! Спасибо! ![]() ![]() <br>... skipped...<br> А вот как теперь ее выгрузить, что бы пересобрать, например? Т.е. что бы эта dinamo.dll освободилась! Ответ краткий - никак. Серьезно. Подробнее - грузить ее в отдельный AppDomain и делать ему Unload. Тогда выгрузятся все сборки в него загруженные |
Сообщ.
#7
,
|
|
|
Так, тогда придется делать некий менеджер, который будет постоянно прибавлять порядковый номер файла (библиотеки) при сборке и в следующий раз загружить именно его! Криво. Но что делать? Раз так задача стоит.
![]() |
Сообщ.
#8
,
|
|
|
Цитата DarkKo, 15.09.03, 13:14:08 Так, тогда придется делать некий менеджер, который будет постоянно прибавлять порядковый номер файла (библиотеки) при сборке и в следующий раз загружить именно его! Криво. Но что делать? Раз так задача стоит. ![]() Зачем??? Сборка уже в метаданных содержит номер версии. А домен придется перегружать при изменении версии, вот и весь менеджер Assembly.GetName().Version |
Сообщ.
#9
,
|
|
|
Хорошая мысль с доменом! Это гениально.
А почему у меня вот так сразу не загружается библиотека в домен? (на третьей строчке ошибка) ![]() ![]() <br>AppDomain Domen = AppDomain.CreateDomain("Domen Addition Dll");<br>Assembly SecondScriptAssembly;<br>SecondScriptAssembly = Domen.Load(filename);<br> |
Сообщ.
#10
,
|
|
|
Цитата DarkKo, 15.09.03, 14:29:53 AppDomain Domen = AppDomain.CreateDomain("Domen Addition Dll"); Assembly SecondScriptAssembly; SecondScriptAssembly = Domen.Load(filename); Попробуй так. ![]() ![]() <br>// Set up the Evidence<br>Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;<br>Evidence evidence = new Evidence(baseEvidence);<br>evidence.AddAssembly("(some assembly)");<br><br>// Create the AppDomain <br>AppDomain newDomain = AppDomain.CreateDomain("newDomain", evidence);<br> Просто проблема при загрузке сборки в домен, не являющийся текущим для приложения. Смотри AppDomain.Load раздел Remarks |
Сообщ.
#11
,
|
|
|
Зачем в evidence добавлять сборку - не понимаю.
Пытаюсь сделать вот так: ![]() ![]() <br>AppDomain Domen = AppDomain.CreateDomain("NewDomain");<br>try<br>{<br>Object fromdll = Domen.CreateInstanceFromAndUnwrap(filename, "dinamo.PrintMessage");<br>}<br> И при этом ловлю exception: SerializationException Который мне говорит, что мойе сборки (перечисляет ее имя) найти не может. |
Сообщ.
#12
,
|
|
|
кстати при создании домена передай еще сетап с ShadowCopyFiles = true - тогда сможешь сборку на новую заменить
Я не помню, там были какие-то траблы с этим, но сейчас проверить не могу... надо поэкспериментировать, например загрузить сборку из Гака или передать strong name. Насчет strong name особенно актуально если у тебя фреймворк 1.1 |
Сообщ.
#13
,
|
|
|
Знаешь что я подумал! Я полумал, что текущий домен можно сделать с ShadowCopyFiles = true. Посмотрим, получится или нет.
Framework у меня действительно 1.1 А с GAC я не пробовал. Чем это поможет? |
Сообщ.
#14
,
|
|
|
Когда на текущий домен ставишь SetShadowCopyFiles(), то пересборка dll возможна. Т.к. библиотека была куда-то скопирована и от туда юзается. Но при следующем вызове LoadFrom уже не получается достать новую библиотеку. Как он себе копию сделал, так ее и использует.
А в новый домен так и не получается сборку засосать. |
Сообщ.
#15
,
|
|
|
Да ты прав, я наверное глупость сказал вчера, совсем забыл, что при загрузке сборки в нетекущий домен - она автоматом загрузится и в текущий. Иначе невозможен обмен данными. Извиняй - давно это уже было
Если у тебя 1.1, то скорее всего он от тебя хочет strong name сборки. ГАК я посоветовал чисто для эксперимента, типа найдет/не найдет И последнее: учти что при загрузке сборки в отдельный домен все взаимодействие пойдет через ремоутинг, со всеми вытекающими: 1) Передаваемые в качестве параметров и возвращаемого значения типы должны быть сериализуемыми. 2) Сборка должна быть загружена и в вызывающем домене и в выполняющем 3) Если объект передается по значению, то при попытке доступа к нему тебе отдадут копию. 4) Статик-переменные в разных доменах разные 5) Если объект передается по ссылке то доступ к нему происходит через прокси, что сказывается на скорости вызова не в лучшую сторону А подгрузить новую он и не даст, т.к. это равнозначно выгрузке старой! Кто будет проверять совместимость типов например? Представь что у тебя у клиента остались ссылки на типы из старой сборки, а тут ты раз и меняешь ее на новую. в .NET такое никогда не позволяется, код должен быть безопасен. Наверное среда могла быть проверять и кидать что-нить типа TypeUnloadException но тогда извини - теряем в производительности. В общем хочешь пересобирать на лету - экспериментируй с отдельным доменом |
Сообщ.
#16
,
|
|
|
Смотри на пример в доке AppDomain.Load, конкретнее на MyResolver. Если у тебя его нет - скажи я скопирую сюда. Там упоминается, что нужен стронг нэйм, а так как его нет, сборка грузится как байтовый массив. Пробуй
|
Сообщ.
#17
,
|
|
|
Я всех порвал!
Блин, получилось! ![]() Во как надо! ![]() ![]() <br>AppDomainSetup appDomainSetup = new AppDomainSetup ();<br>appDomainSetup.ShadowCopyFiles = "true";<br>AppDomain Domen = AppDomain.CreateDomain ("AppDomainFriendlyName", AppDomain.CurrentDomain.Evidence, appDomainSetup);<br>Domen.SetShadowCopyFiles();<br>Object fromdll = Domen.CreateInstanceFromAndUnwrap(dirrectory + name, "PrintMessage");<br>Console.Write(fromdll.ToString()+"\n");<br>Console.Write(fromdll.GetType().ToString()+"\n");<br>MethodInfo Method = fromdll.GetType().GetMethod("Message");<br>Method.Invoke(fromdll,null);<br>AppDomain.Unload(Domen);<br> Удивительно только что приходится повторный раз вызывать Domen.SetShadowCopyFiles(); , ведь в setup я уже прописал, appDomainSetup.ShadowCopyFiles = "true";. При этом сама библиотека вот так написана. ![]() ![]() <br>using System;<br>using System.Runtime.InteropServices;<br>public class PrintMessage: MarshalByRefObject<br>{<br> public void Message()<br> {<br> Console.Write("Inside dll module ONE MORE TIME\n");<br> }<br>};<br> Тоже самое но с namecpase (ну в библиотечном файле) реализовать не получилось. |
Сообщ.
#18
,
|
|
|
2kl
Кстати, когда я пробовал чеоез AppDomain.Load - он мне конкретно отказывался находить файл. ![]() Сейчас посмтрю то что ты посоветовал. |
Сообщ.
#19
,
|
|
|
Кстати, вот как релизован там MyResolver - это просто создается тип и грузится в dll?
Я так понимаю, что это нужно, для того что бы переопределять содержимое dll в ран-тайм. Но не перезагружать. |
Сообщ.
#20
,
|
|
|
Цитата DarkKo, 16.09.03, 11:00:06 Кстати, вот как релизован там MyResolver - это просто создается тип и грузится в dll? Я так понимаю, что это нужно, для того что бы переопределять содержимое dll в ран-тайм. Но не перезагружать. loadfile сборку находит а AppDomain.Load нет. Вот они перехватывают событие разрешения имени сборки и грузят ее как массив байт |
Сообщ.
#21
,
|
|
|
Кстати, про быстроту загрузки.
Если не выгружать сборку (в смысле домен), а просто загружать ее и загружать. Как можно убыстрить подкачку dll. Вот первый раз (в отладчике) оа у меня загружается аж 1 секунду. А последующие разы - аж до 1мс. Хотелось бы первый раз порядка миллисекунд, а последующие раз в 10 быстрей. 2kl Ты говорил про проверку версии. Цитата Assembly.GetName().Version Как мне найти эту самую Assembly, что бы сравнить со сборкой, которую я загружаю, и как узнать версию сборки, которую я загружаю не загрузив ее? |
Сообщ.
#22
,
|
|
|
Цитата DarkKo, 16.09.03, 12:32:11 Ты говорил про проверку версии. Как мне найти эту самую Assembly, что бы сравнить со сборкой, которую я загружаю, и как узнать версию сборки, которую я загружаю не загрузив ее? Ну как, либо AppDomain.CurrentDomain.GetAssemblies, перебираешь их и находишь свою по имени, либо через статик метод Assembly.GetAssembly куда передаешь тип своего объекта (который живет в этой сборке) |
Сообщ.
#23
,
|
|
|
При передачи ссылки на обхект из одного домен а в другой возникают жуткие проблемы. Хотя казалось, что код работает, но другой такойже код - уже не работает.
Я вычитал: Цитата Однако ручная сериализация – это дополнительный код, а значит, и дополнительное время, ну и разумеется, дополнительные ошибки, а стало быть, снова время и нервы. Если учесть, что стандартная сериализация в .NET обеспечивает автоматическую сериализацию графов объектов (обеспечивая его восстановление при десериализации, с восстановлением всех связей), то становится понятным, что к ручной сериализации стоит прибегать, только имея серьезные основания. Если же сериализуемый объект содержит ссылки на MarshalByRefObject (передаваемые по ссылке объекты), то сериализация существенно усложняется, так как придется залезть в довольно низкоуровневые вещи, чтобы обеспечить передачу ссылки на объект в другой процесс (домен приложения, контекст). http://www.rsdn.ru/article/dotnet/DotNetSerial.xml У меня как раз такой вот объект MarshalByRefObject, и как раз вылезают (при Invoke метода) эксепшены на счет сериализации. Подскажите, где мне мозгов не хватает, что бы мне сдалать стабильный, полностью понятный код. |
Сообщ.
#24
,
|
|
|
Ты внимательно читал мой пост №14?
|