Здравствуйте, Jolly Roger, Вы писали:
_FR>>А какой смысл в написании враперов с файнализатором? Они и так уже ж есть.
JR>Похоже, у меня к вечеру совсем плохо с соображалкой Вы не могли-бы чуть более развёрнуто уточнить, что Вы имеете в виду? Наследоваться от CriticalFinalizerObject потомков? Я в принципе это и подразумевал под "реализацией"
Да просто в таком вот коде:
IServer server = CreateServerObject(...);
foreach(int i = 0; i < server.Documents.Length; ++i)
{
server.Documents[i].foo();
}
и без всяких дополнительных враперов у "server" и других временных объектов при файнализации будут вызваны Release и свой врапер с файнализатором не имеет смысла.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, Angler, Вы писали:
A>обязан быть переписан в следующую колбасину???:
Думаю, да. Или писать врапперы, в них либо реализовывать деструктор, либо наследовать IDisposable и заворачивать в using. Или и то, и другое. Без рефакторинга вряд-ли удастся обойтись.
Я в свое время решил проблему через создание отдельного AppDomain, в котором выполнялась вся работа с COM, после чего перед завершением работы приложения этот AppDomain уничтожался. В результате правильно освобождались все созданные в нем COM-объекты.
, хотелось бы узнать, возможно я пытаюсь делать что-то c СОМ не так? A>Тоесть следующий кусок:
A>IServer server = CreateServerObject(...);
A>foreach(int i = 0; i < server.Documents.Length; ++i)
A>{
A> server.Documents[i].foo();
A>}
A>обязан быть переписан в следующую колбасину???:
Даже и ваш вариант не совсем верен:
A>IServer server = CreateServerObject(...);
A>try
A>{
A> IDocumentList docList = server.Documents;
A> try
A> {
A> foreach(int i = 0, length = docList.Length; i < length; ++i)
A> {
A> IDocument doc = docList[i];
A> try
A> {
A> doc.foo();
A> }
A> finally
A> {
A> Marshal.ReleaseComObject(doc);
A> }
A> }
A> }
A> finally
A> {
A> Marshal.ReleaseComObject(docList);
A> }
A>}
A>finally
A>{
A> Marshal.ReleaseComObject(server);
A>}
Я как-то писал какую-то автоудалялку для этих целей (через юзинги), но сильно дело она не улучшала: сказывается отсутствие возможности автоматического вызова разрушителей и перегрузки стрелки
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, Jolly Roger, Вы писали:
A>>обязан быть переписан в следующую колбасину???:
JR>Думаю, да. Или писать врапперы, в них либо реализовывать деструктор,
А какой смысл в написании враперов с файнализатором? Они и так уже ж есть.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>А какой смысл в написании враперов с файнализатором? Они и так уже ж есть.
Похоже, у меня к вечеру совсем плохо с соображалкой Вы не могли-бы чуть более развёрнуто уточнить, что Вы имеете в виду? Наследоваться от CriticalFinalizerObject потомков? Я в принципе это и подразумевал под "реализацией"
Здравствуйте, _FRED_, Вы писали:
_FR>Да просто в таком вот коде: _FR>
_FR>IServer server = CreateServerObject(...);
_FR>foreach(int i = 0; i < server.Documents.Length; ++i)
_FR>{
_FR> server.Documents[i].foo();
_FR>}
_FR>
_FR>и без всяких дополнительных враперов у "server" и других временных объектов при файнализации будут вызваны Release и свой врапер с файнализатором не имеет смысла.
Вы уверены? Дело в том, что я проверил — накидал нативную DLL и передал из неё интерфейс в приложение на C#, запустил это дело под отладчиком и сел на релиз этого объекта. Так вот осталась одна незарелизенная ссылка Я посмотрел рефлектором, там создаётся _ComObject и есть вызовы Marshal.ReleaseComObject, но финализатора вроде как нету Полистал MSDN, там упоминают автогенерируемый RCW, который вроде как и должен у этого _ComObject дёргать ReleaseSelf. Может дело в версии фреймворка? Я под 3.5 проверял.
Хотя конечно мог и какую-нибудь идиотскую ошибку сделать, чуть позже еще раз проверю.
Паршиво это всё
В общем сделать правильно можно множеством способов, но все они увы — корявые... Самый красивый был бы конечно враппер с перегруженным -> аля _com_ptr
Возможно кто-то предложит менее корявый способ, чем приведённые мной варианты:
Вариант 1 — вложенные try/finally под каждый пук. приводил выше.
[...]
Вариант 3 — регистрировать самому все ссылки. Вроде получше, но затраты в виде списка...
using (ComObjectsStorage storage = new ComObjectsStorage())
{
InDesign.Application app = storage.Register(GetInDesignApplication());
InDesign.Documents documents = storage.Register(app.Documents);
if (documents.Count == 0)
return;
InDesign.Objects selection = storage.Register(app.Selection as InDesign.Objects);
if (selection == null || selection.Count == 0)
return;
object firstSelectedObject = storage.Register(selection[0]);
if (firstSelectedObject is InDesign.InsertionPoint)
{
//...
}
}
class ComObjectsStorage : IDisposable
{
public void Dispose()
{
objects.ForEach(obj => Marshal.ReleaseComObject(obj));
}
public T Register<T>(T obj)
where T : class
{
objects.Add(obj);
return obj;
}
private List<object> objects = new List<object>();
}
Вариант 3 — врапперы. нда... без без перегрузки оператора -> и деструкторов, просто отвратительно...
using (ApplicationWrapper app = new ApplicationWrapper())
using (InddCollectionWrapper<InDesign.Document> documents = app.Documents)
{
if (documents.Count == 0)
return;
using (SelectionWrapper selection = app.Selection)
{
if (selection.Count == 0)
return;
using (ComObjectWrapper<object> selectedObject = new ComObjectWrapper<object>(selection[0]))
{
if (selectedObject.RealObject is InDesign.InsertionPoint)
{
//...
}
}
}
}