Прежде всего, извиняюсь за длину ...
У меня есть приложение Host / Plugin, похожее на MAF.Мы не используем ни одно из System.Addin или связанных пространств имен, поскольку это настраиваемая архитектура подключаемых модулей с несколькими доменами приложений в игре.Host UI (пользовательский интерфейс) работает в своем собственном цикле приложений (AppDomain).При двойном щелчке элемента в представлении списка происходит следующее:
private static void StartPeripheralModule(string modName)
{
AppDomain domain = AppDomain.CreateDomain(modName);
// add to appdomains collection
HostDomains[modName] = domain;
// instances the module for access to the module's Start() method
IModule module = (IModule)domain.CreateInstanceAndUnwrap(
ModuleManager.Modules[modName].Name,
ModuleManager.Modules[modName].EntryPoint.FullName);
// instance the adapter (inherits MBR)
module.Adapter = new ModuleAdapter(modName, module); // also saves a ref. to the IModule object
// publish events decorated with [Serializable]
module.Adapter.ModuleStarted += new ModuleAdapter.ModuleStartEventHandler(Adapter_ModuleStarted);
module.Adapter.ModuleStopped += new ModuleAdapter.ModuleStopEventHandler(Adapter_ModuleStopped);
module.Adapter.ModuleFaulted += new ModuleAdapter.ModuleFaultEventHandler(Adapter_ModuleFaulted);
// add to adapters collection
HostAdapters[modName] = module.Adapter;
// asynchronous startup
Action startup = module.Start;
startup.BeginInvoke(null , null);
}
В module.Start()
:
[STAThread]
public void Start( )
{
// do Start
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MdiForm = new UnitMDIForm();
MdiForm.FormClosed += new FormClosedEventHandler(MdiForm_FormClosed);
adapter.OnModuleStarted(new ModuleAdapter.ModuleStartEventArgs(adapter));
Application.Run(MdiForm);
}
MdiForm_FormClosed
просто сообщает хосту, что модуль модулябыть закрытым через пользовательский интерфейс плагина и начать процедуру закрытия на AppDomain
.Плагин модуля запускается как положено, и событие OnModuleStarted
работает нормально.При повторном щелчке элемента списка дважды модуль должен выключиться:
public static void UnloadInstance(string modName)
{
Action shutdown = HostAdapters[modName].Module.Shutdown;
IAsyncResult iaRes = shutdown.BeginInvoke(null , null);
while (!iaRes.IsCompleted) // poll wait state
{
Thread.Sleep(250);
hostListener.Write(".");
}
}
Функция выключения в плагине модуля:
public void Shutdown( )
{
if (MdiForm.InvokeRequired)
{
MdiForm.Invoke((MethodInvoker)delegate
{
MdiForm.FormClosed -= MdiForm_FormClosed;
Application.Exit();
});
}
else
{
MdiForm.FormClosed -= MdiForm_FormClosed;
Application.Exit();
}
adapter.OnModuleStopped(new ModuleAdapter.ModuleStopEventArgs(adapter));
}
Причина, по которой событие MdiForm.FormClosed не подписано наэто предотвратить двойную стрельбу.Как только Application.Exit()
я получаю 1 - 2 '.'(точки) из механизма опроса, а затем:
Первое случайное исключение типа 'System.Threading.ThreadAbortException' произошло в mscorlib.dll Первое случайное исключение типа 'System.Threading.ThreadAbortException'произошло в UnitTestWinForm.dll Исключение типа «System.Threading.ThreadAbortException» произошло в UnitTestWinForm.dll, но не было обработано в коде пользователя
Излишне говорить, что мы никогда не достигнем нашего события OnModuleStopped
, гдемы официально выгружаем AppDomain, удаляем его и адаптер из наших коллекций.Сейчас я вставляю блок try / catch, чтобы узнать, смогу ли я получить что-нибудь еще от ошибок.Из того, что я понимаю, я следую правильной процедуре при выходе из цикла сообщений приложения, а затем выгрузки домена.Это дает модулю возможность очищать свои ресурсы и т. Д.
Может кто-нибудь сказать мне, что я делаю неправильно и / или как я должен делать это по-другому?