Com и Wpf

Тема в разделе ".NET", создана пользователем Valdocco, 1 апр 2010.

Статус темы:
Закрыта.
  1. Valdocco

    Valdocco Гость

    Доброго дня суток, уважаемые участники форума.
    Для разработки я использую Visual Studio .NET 2008 версии 9.0.21022.8 .NET Framework 3.5 SP1. Мое приложение использует COM+ и COM библиотеку, написанную на C++ в МС студии 6.0.
    Хочу использовать в своем решении новую технологию микрософта - WPF. Я создал форму WPF, добавил туда меню и несколько других элементов управления. По нажатию на кнопку в меню, должна вызываться одна из функций COM библиотеки, с использованием COM+. Функция отрабатывает корректно, все в порядке. Но, если после этого начать кликать по другим элементам управления на форме, возникнет эксепшн "AccessViolationException", или другая пустая ошибка, при которой приложение просто вылетает. Причем это происходит не сразу, а через некоторое время. Если по элементам управления не кликать, эксепшена не будет.
    Провел эксперимент, сделал тоже самое через System.Windows.Forms. Там все работает нормально, и при этих же действиях эксепшена не возникает.
    Как думаете, в чем может быть дело?
     
  2. LuMee

    LuMee Well-Known Member

    Регистрация:
    2 май 2006
    Сообщения:
    477
    Симпатии:
    0
    Хорошо бы увидеть исходник.
     
  3. Dron247

    Dron247 Гость

    Попробуйте использовать Command, мне кажется что вся работа с COM у вас происходит в обработчике события щелчка (возможно только кажется, каков вопрос, таков ответ). Создайте объект-обёртку для вызовов com и дергайте его методы из обработчика, использую такой подход, проблем не возникало
     
  4. Valdocco

    Valdocco Гость

    Код (Text):
    //ПЕРЕМЕННАЯ НУЖНОГО КЛАССА COM
    AprilSvr AprilServer;
    //ПОЛУЧАЕМ ЕГО С COM+ С УКАЗАНИЕМ АДРЕСА СЕРВЕРА
    Type ObjectType = Type.GetTypeFromProgID("AprilServer.AprilSvr", "localhost");             
    AprilServer = (AprilSvr)(Activator.CreateInstance(ObjectType));

    //ВЫЗЫВАЕМ НУЖНЫЙ МЕТОД
    AprilServer.Perform(null, SvrParams.GetAllData(), out ObjectSvrResult,
    null, out Recordset, out RCS2, out RCS3);
    SvrParams.GetAllData() - SvrParams - тоже класс КОМ, в него упаковываются параметры вызова. Метод GetAllData() - преобразует его в VARIANT.

    Recordset, RCS2, RCS3 - комовские рекордсеты.

    ObjectSvrResult - заглушка типа object.

    Метод AprilServer.Perform отрабатывает корректно, а вот после нажатия на кнопки интерфейса, через некоторое время возникает пустая ошибка и вылетает.

    Обертка для КОМ объекта уже существует, но это дела не меняет, все равно рушится.
    Может ли дело быть непосредственно в ком объекта? С консоли таких ошибок вроде не возникает.
     
  5. Dron247

    Dron247 Гость

    Покажите код обработчика меню, интересно как вызываете, и как насчет финализации COM объекта, не забываете? а ссылочки на него обнулять?
     
  6. Valdocco

    Valdocco Гость

    Объявление меню:

    Код (Text):
     <MenuItem Name="Connect" Header="Подключиться..." Click="Connect_Click" />
    Код обработчика:

    Код (Text):
    private void Connect_Click(object sender, RoutedEventArgs e)
    {
    //СОЗДАЕТСЯ ОБЪЕКТ КЛАССА-ПОСРЕДНИКА, КОТОРЫЙ ИНКАПСУЛИРУЕТ КОМ
    manager = new Manager("localhost");
    DataTable Roots;
    //ВЫЗЫВАЕМ КОМ МЕТОД ЧЕРЕЗ ПОСРЕДНИКА
    manager.GetRoots(out Roots);

    }
    Для уничтожения КОМ объекта я использую деструктор класса-посредника. AprilServer - КОМ объект.

    Код (Text):
    ~Adapter()
    {
    Marshal.ReleaseComObject(AprilServer);
    }
    Я так понимаю, при вызове этой конструкции ссылки на КОМ объект должны убираться.
     
  7. Dron247

    Dron247 Гость

    Попробуйте реализовать в обёртке IDisposable, ведь мы не можем знать, когда отработает деструктор.

    <!--shcode--><pre><code class='cs'>public class Wrapper : IDisposable{

    DataTable GetRoots() { ... }

    ~Wrapper() { Dispose(); }

    public void Dispose(){
    Marshal.ReleaseComObject(AprilServer);
    }
    }[/CODE]
    реализовав такую штуку теперь можем сделать так:
    <!--shcode--><pre><code class='cs'> using(var w = new Wrapper()){
    //Do something
    //Do something else
    var Roots = w.GetRoots();
    }[/CODE]

    что как-бы даёт гарантию, что Dispose() отработает когда мы хотим (по идее). Попробуйте это, если не прокатит будем копать в сторону вызовов, сам wpf виноват быть не должен, хотя не скрою, он болезненно относился к ref параметрам функций, правда ref были на элементы управления

    PS код не проверял=)
     
  8. Valdocco

    Valdocco Гость

    К сожалению, сделав так, результата добиться не удалось. Впрочем, я пробовал раньше вызывать явно освобождение КОМ объекта и все равно была ошибка.
    Только что сделал эксперимент, сделал на windows.forms такой же интерфейс - там все работает корректно, не вылетает. А тут, где-то после 10 нажатий по разным кнопкам происходит сбой.
     
  9. Valdocco

    Valdocco Гость

    Господа, спасибо за помощь, проблема решена. Вот решение:
    Код (Text):
              //ПОМЕЩАЕМ ДАННЫЕ ИЗ SvrParams В ОБДЖЕКТ
    object ObjSvrParams = SvrParams.GetAllData();
    //УНИЧТОЖАЕМ SvrParams ДО ВЫЗОВА ПРОЦЕДУРЫ. ЕСЛИ ЭТО СДЕЛАТЬ ПОСЛЕ,
    // ТО SafeArray, КОТОРЫЙ ЛЕЖИТ В ОСНОВЕ SvrParams БЛОКИРУЕТСЯ И НЕ УНИЧТОЖАЕТСЯ
    // И ВОЗНИКАЕТ ОШИБКА ЗАПИСИ В ЗАЩИЩЕННУЮ ПАМЯТЬ
    Marshal.ReleaseComObject(SvrParams);
    //ВЫЗОВ УДАЛЕННОГО МЕТОДА
    AprilServer.Perform(null, ObjSvrParams, out ObjectSvrResult,
    null, out Recordset, out RCS2, out RCS3);
    Если выполнять процедуру до уничтожения объекта, то команда:
    Код (Text):
    HRESULT hr = SafeArrayDestroy(m_Data);
    которая уничтожает SafeArray в SvrParams выдает ошибку и это в итоге сказывается на работе приложения .NET, которое использует ДЛЛку.
     
Загрузка...
Статус темы:
Закрыта.

Поделиться этой страницей