Корректное использование COM
От: Angler Россия  
Дата: 28.09.10 12:59
Оценка:
В продожение к http://rsdn.ru/forum/dotnet/3975371.1.aspx
Автор: Angler
Дата: 28.09.10
, хотелось бы узнать, возможно я пытаюсь делать что-то c СОМ не так?
Тоесть следующий кусок:


IServer server = CreateServerObject(...);
foreach(int i = 0; i < server.Documents.Length; ++i)
{
   server.Documents[i].foo();
}



обязан быть переписан в следующую колбасину???:


IServer server = CreateServerObject(...);
try
{
  IDocumentList docList = server.Documents;
  try
  {
     foreach(int i = 0; i < server.Documents.Length; ++i)
     {
        IDocument doc = server.Documents[i];
        try
        {
           doc.foo();
        }
        finally
        {
           Marshal.ReleaseComObject(doc);
        } 
     }
  }
  finally
  {
     Marshal.ReleaseComObject(docList);
  }
   
}
finally
{
   Marshal.ReleaseComObject(server);
}



???
Re: Корректное использование COM
От: Jolly Roger  
Дата: 28.09.10 16:56
Оценка: 4 (1)
Здравствуйте, Angler, Вы писали:

A>обязан быть переписан в следующую колбасину???:


Думаю, да. Или писать врапперы, в них либо реализовывать деструктор, либо наследовать IDisposable и заворачивать в using. Или и то, и другое. Без рефакторинга вряд-ли удастся обойтись.
"Нормальные герои всегда идут в обход!"
Re: Корректное использование COM
От: aloch Россия  
Дата: 29.09.10 06:32
Оценка: 4 (1)
Здравствуйте, Angler, Вы писали:

Я в свое время решил проблему через создание отдельного AppDomain, в котором выполнялась вся работа с COM, после чего перед завершением работы приложения этот AppDomain уничтожался. В результате правильно освобождались все созданные в нем COM-объекты.


Re: Корректное использование COM
От: _FRED_ Черногория
Дата: 29.09.10 08:47
Оценка:
Здравствуйте, Angler, Вы писали:

A>В продожение к http://rsdn.ru/forum/dotnet/3975371.1.aspx
Автор: Angler
Дата: 28.09.10
, хотелось бы узнать, возможно я пытаюсь делать что-то 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.
Re[2]: Корректное использование COM
От: _FRED_ Черногория
Дата: 29.09.10 08:48
Оценка:
Здравствуйте, Jolly Roger, Вы писали:

A>>обязан быть переписан в следующую колбасину???:


JR>Думаю, да. Или писать врапперы, в них либо реализовывать деструктор,


А какой смысл в написании враперов с файнализатором? Они и так уже ж есть.
Help will always be given at Hogwarts to those who ask for it.
Re[3]: Корректное использование COM
От: Jolly Roger  
Дата: 29.09.10 12:35
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>А какой смысл в написании враперов с файнализатором? Они и так уже ж есть.


Похоже, у меня к вечеру совсем плохо с соображалкой Вы не могли-бы чуть более развёрнуто уточнить, что Вы имеете в виду? Наследоваться от CriticalFinalizerObject потомков? Я в принципе это и подразумевал под "реализацией"
"Нормальные герои всегда идут в обход!"
Re[4]: Корректное использование COM
От: _FRED_ Черногория
Дата: 29.09.10 12:39
Оценка: 7 (1)
Здравствуйте, 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.
Re[5]: Корректное использование COM
От: Jolly Roger  
Дата: 29.09.10 13:11
Оценка:
Здравствуйте, _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 проверял.

Хотя конечно мог и какую-нибудь идиотскую ошибку сделать, чуть позже еще раз проверю.
"Нормальные герои всегда идут в обход!"
Re: Корректное использование COM
От: Angler Россия  
Дата: 25.11.10 17:01
Оценка:
Паршиво это всё
В общем сделать правильно можно множеством способов, но все они увы — корявые... Самый красивый был бы конечно враппер с перегруженным -> аля _com_ptr

Возможно кто-то предложит менее корявый способ, чем приведённые мной варианты:

Вариант 1 — вложенные try/finally под каждый пук. приводил выше.
[...]

Вариант 2 — в лоб. хочется блевать((
InDesign.Application app = GetInDesignApplication();
InDesign.Documents documents = null;
InDesign.Objects selection = null;
object firstSelectedObject = null;
try
{                        
    documents = app.Documents;
    if (documents.Count == 0)
        return;

    selection = app.Selection as InDesign.Objects;
    if (selection == null || selection.Count == 0)
        return;

    firstSelectedObject = selection[0];
    if (firstSelectedObject is InDesign.InsertionPoint)
    {
        //...
    }
}
finally
{
    Marshal.ReleaseComObject(app);
    Marshal.ReleaseComObject(documents);
    Marshal.ReleaseComObject(selection);
    Marshal.ReleaseComObject(firstSelectedObject);
}


Вариант 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)
            {
                //...
            }
        }                        
    }                                     
}



Бяда прям какая-то
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.