Как на C# (вообще на .Net) создать COM-сервер, но не библиотеку классов, а EXE, out-of-proc. Как создать Proxy Stub?
Где можно конкретно об этом почитать?
Здравствуйте, dmitry_npi, Вы писали:
_>Как на C# (вообще на .Net) создать COM-сервер, но не библиотеку классов, а EXE, out-of-proc. Как создать Proxy Stub?
имхо никак.
Опыт — это такая вещь, которая появляется сразу после того, как была нужна...
Здравствуйте, dmitry_npi, Вы писали:
_>Как на C# (вообще на .Net) создать COM-сервер, но не библиотеку классов, а EXE, out-of-proc. Как создать Proxy Stub? _>Где можно конкретно об этом почитать?
насколько я помню System.EnterpriseServices может в этом помочь... попытай Влада (VladD2) он с этим копался...
а вообще создать out of proc сервер можно... ставь в параметрах "Make Assembly Com Visible", прописывай Guid'ы и кастомизируй регистрацию... как это делать тут писалось уже несколько раз...
... << RSDN@Home 1.2.0 alpha rev. 789>>
Если при компиляции и исполнении вашей программы не происходит ни одной ошибки — это ошибка компилятора :)))
Здравствуйте, dmitry_npi, Вы писали:
_>Как на C# (вообще на .Net) создать COM-сервер, но не библиотеку классов, а EXE, out-of-proc. Как создать Proxy Stub? _>Где можно конкретно об этом почитать?
Любой C# класс является/может быть COM сервером. Даже наследовать этот класс не надо от специальных базовых классов. По этому, задача сводится к:
1. Правильной регистрации сервера
2. Вызове CoRegisterClassObject
ЛИБО, использовании COM+ или стандартного сурогата.
вторая задача банальна, так как для вызова CoRegisterClassObject написан банальный врапер RegisterTypeForComClients. С остальным сам справишься?
код работает классно, только вот где почитать, как на шарпе понять, когда можно уничтожать свой out-proc server?
надо же как то поймать момент, когда последний COM клиент уйдет, подождать еще секунд 5ть и выгрузить процесс, как это было в ATL.
например у меня вместо ожидания клавиши висит форма, когда ей посылать сообщение "закрыться" или какой есть механизм?
куда копать подскажите?
то есть по сути вопрос такой, как ловить момент когда счетчик ссылок на все мои интерфейсы станет равен нулю?
а то неприятно оставлять в памяти загруженный процесс.
from __python__ import paradigma
from __future__ import generators
from __waterfall__ import power
неужели никто не знает как считать ссылки?
наверняка кто-то сталкивался с тем, что процесс остается в памяти.
или никому не мешают пару тройку забытых EXE-ов в раме?
from __python__ import paradigma
from __future__ import generators
from __waterfall__ import power
Здравствуйте, __WaterFall__, Вы писали:
__W>неужели никто не знает как считать ссылки? __W>наверняка кто-то сталкивался с тем, что процесс остается в памяти. __W>или никому не мешают пару тройку забытых EXE-ов в раме?
Выгружаться можно тогда, когда на сервере нет созданных обьектов.
Соответственно тебе надо в конструкторе твоего обьекта увеличивать счётчик, а в реализации IDisposable pattern-а уменьшать. Видимо только так.
Здравствуйте, Tom, Вы писали:
Tom>Здравствуйте, __WaterFall__, Вы писали:
__W>>неужели никто не знает как считать ссылки? __W>>наверняка кто-то сталкивался с тем, что процесс остается в памяти. __W>>или никому не мешают пару тройку забытых EXE-ов в раме?
Tom>Выгружаться можно тогда, когда на сервере нет созданных обьектов. Tom>Соответственно тебе надо в конструкторе твоего обьекта увеличивать счётчик, а в реализации IDisposable pattern-а уменьшать. Видимо только так.
в теории я понимаю что так, но к чему прикрутить? конструктору какого объекта?
вот, например, у меня out-proc сервер зарегистрирован как EXE.
первый вызов из кома приходит в статическую ф-цию Main статического класса
__W>к какому бы классу не прикручивал IDisposable — не вызывается public void Dispose()
Dispose вызовется только при сборке мусора, данный способ для детерминированного вызова Dispose не подходит. Реализовывать IDisposable надо у вашего COM обьекта, реализованного на .NET.
В принципе, что бы иметь детерминированное освобождение обьекта, можно попробовать написать на C++ COM обьект, который будет агрегировать .NET обьект и вызывать Dispose при последнем вызове Release. Можно наверное даже сделать такой обьект универсальным, и моникер к нему написать.
Здравствуйте, Tom, Вы писали:
Tom>Dispose вызовется только при сборке мусора, данный способ для детерминированного вызова Dispose не подходит. Реализовывать IDisposable надо у вашего COM обьекта, реализованного на .NET.
что-то неправильно с этим Dispose(), не вызывается он даже при сборке мусора.
прикрутил IDisposable к классу так
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public sealed class Commands : IDisposable
{
public Commands()
{
MessageBox.Show("Create");
}
~Commands()
{
MessageBox.Show("Destroy");
}
public void ExtCommand(object arguments)
{
//
}
public void Dispose()
{
MessageBox.Show("Dispose");
// todo: send WM_QUIT to Form
}
}
Здравствуйте, __WaterFall__, Вы писали:
__W>Здравствуйте, Tom, Вы писали:
Tom>>Dispose вызовется только при сборке мусора, данный способ для детерминированного вызова Dispose не подходит. Реализовывать IDisposable надо у вашего COM обьекта, реализованного на .NET.
__W>что-то неправильно с этим Dispose(), не вызывается он даже при сборке мусора.
Естественно нге будет, в такой реализации посмотри как стандартно реализуется IDisposable паттерн
Здравствуйте, Tom, Вы писали:
Tom>Dispose вызовется только при сборке мусора, данный способ для детерминированного вызова Dispose не подходит. Реализовывать IDisposable надо у вашего COM обьекта, реализованного на .NET.
мне кажется что Dispose вызывается только если объект заворачивать в using () {}, это не мой случай, меня вызывают COM клиенты, объект создается при помощи CCW. Причем Dispose вызыватся не при сборке мусора, а сразу же при достижении конца области видимости. Во всяком случае, так себя ведет компилятор. Dispose вообще у меня не вызывается, если объект не заворачивать в using. Мне не удалось добиться вызова Dispose для обычных объектов.
Tom>В принципе, что бы иметь детерминированное освобождение обьекта, можно попробовать написать на C++ COM обьект, который будет агрегировать .NET обьект и вызывать Dispose при последнем вызове Release. Можно наверное даже сделать такой обьект универсальным, и моникер к нему написать.
в принципе, мне деструктора Commands::~Commands() достаточно, не хочу писать никаких агрегирований, надо было не связываться с дотнетом и писать на плюсах, но такое требование — надо на С#.
не понял про моникер, надо будет матчасть посмотреть...
пока есть такое решение.
на форму ставиться таймер, который раз в 5ть секунд колбасит GC.Collect().
может какие настройки есть у Garbage Collector-a, чтобы без таймера?
сборка мусора вызовет наш деструктор Commands::~Commands().
из деструктора вызываем Close() форме, когда ссылки сойдут на 0.
Если COM клиент придет в момент когда уже Close() вызвана, но переключена задача и стоит в очереди сообщение на закрытие, то получится что старая задача жива, тогда, теоретически, новая задача запуститься [еще один процесс MY.EXE], а старый процесс постепенно закроется, когда задача получит свой квант и проколбасит [message pump] месаги в очереди сообщений.
Вроде все на мази?
И спасибо за советы. Почему-то решение находится только когда с кем-то перетрешь тему.
from __python__ import paradigma
from __future__ import generators
from __waterfall__ import power
прекрасно работает решение с периодическим вызовом GC.Collect()
чувствую, что есть более красивое решение, ведь всего лишь надо перехватить момент, когда последний COM client уходит...
но, как всегда, нет времени...
from __python__ import paradigma
from __future__ import generators
from __waterfall__ import power