Com и Wpf

  • Автор темы Valdocco
  • Дата начала
Статус
Закрыто для дальнейших ответов.
V

Valdocco

Гость
#1
Доброго дня суток, уважаемые участники форума.
Для разработки я использую 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. Там все работает нормально, и при этих же действиях эксепшена не возникает.
Как думаете, в чем может быть дело?
 
D

Dron247

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

Valdocco

Гость
#4
Код:
//ПЕРЕМЕННАЯ НУЖНОГО КЛАССА 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 отрабатывает корректно, а вот после нажатия на кнопки интерфейса, через некоторое время возникает пустая ошибка и вылетает.

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

Dron247

Гость
#5
Может ли дело быть непосредственно в ком объекта? С консоли таких ошибок вроде не возникает.
Покажите код обработчика меню, интересно как вызываете, и как насчет финализации COM объекта, не забываете? а ссылочки на него обнулять?
 
V

Valdocco

Гость
#6
Объявление меню:

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

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

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

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

Dron247

Гость
#7
Попробуйте реализовать в обёртке 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 код не проверял=)
 
V

Valdocco

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

Valdocco

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