AccessViolationException из System.Windows.Forms, используя WinFormsHost в WPF - PullRequest
3 голосов
/ 16 февраля 2011

При разработке приложения взаимодействия WPF / WinForms я столкнулся с неприятной проблемой. Я пытался решить эту проблему в течение трех дней, но я не могу добиться успеха. Я сомневаюсь, что могу предоставить достаточно информации, чтобы получить разрешение, но я ищу любого, кто мог бы объяснить что здесь происходит?

Компонентом, который я использую, является AxMapControl (ESRI ArcGIS Engine 9.3.1 SP2), который, насколько я знаю, является нативным кодом в COM-оболочке и представлен как элемент управления WinForms. Компонент встроен в наше клиентское программное обеспечение WPF (.NET 3.5) с использованием WPF WinFormsHost proxy.

Периодически приложение сильно падает с AccessViolationException. Это всегда происходит в ответ на щелчок мышью пользователя на элементе управления картой, но, похоже, нет какой-либо рифмы или причины того, что именно вводит. Трассировка стека всегда одинакова:

System.AccessViolationException: попытка чтения или записи в защищенную память. Это часто указывает на то, что другая память повреждена. в System.Windows.Forms.UnsafeNativeMethods.CallWindowProc (IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam) в System.Windows.Forms.NativeWindow.DefWndProc (Message & m) в System.Windows.Forms.Control.DefWndProc (сообщение & m) в System.Windows.Forms.AxHost.WndProc (сообщение & m) в System.Windows.Forms.Control.ControlNativeWindow.OnMessage (Message & m) в System.Windows.Forms.Control.ControlNativeWindow.WndProc (Message & m) в System.Windows.Forms.NativeWindow.Callback (IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Поскольку исключение, похоже, выбрасывается за пределы любого стека вызовов, инициированного моим кодом, я не могу понять, как перехватить исключение и обработать его программно.

Эта проблема возникает в режиме отладки, а также в сборках выпуска. Однако это происходит не на всех компьютерах, но я смог повторить эту проблему в Windows 7 и XP, а также .NET Framework 3.5 и 4.0.

Проверка того, что происходит в процессе во время сбоя, кажется, что обнаруживается аномалия в том, что в развернутых GAC DLL выполняется несколько операций CreateFileMapping, которые завершаются с ошибкой FILE LOCKED WITH ONLY READERS.

ProcMon screenshot

Это представление было отфильтровано, чтобы показывать только результаты этого типа, но, похоже, это происходит ровно дважды с каждой DLL. Это что-то значит?

Теперь очевидно, что я не знаю, что происходит и как решить эту проблему. Если у вас есть подсказка, не могли бы вы быть добрыми и объяснить мне, с каким типом проблемы я имею дело?

Есть идеи, как я могу отладить эту проблему?

1 Ответ

1 голос
/ 31 марта 2011

Я использую другой элемент управления картой, отличный от ESRI, но мои настройки очень похожи: собственный код карты, обернутый в COM, обернутый в элемент управления Windows Forms, а затем перенесенный в приложение WPF через WindowsFormsHost. И несколько недель назад я получил точно такое же исключение System.AccessViolationException, когда щелкнул карту, с очень небольшим количеством опций для отладки.

Виновник моей проблемы: инициализация базового элемента управления в WPF происходит не так, как я думал - WPF откладывает определенную инициализацию до тех пор, пока представление не станет полностью необходимым / видимым на экране (я предполагаю уменьшить окно / элемент управления время загрузки). В WPF я помещал весь свой код инициализации для базового элемента управления картой в конструктор и обработчик событий (WPF) UserControl.Loaded. Проблема заключалась в том, что WPF вызывает конструктор и вызывает событие Loaded до того, как все действительно будет видно на экране. Таким образом, мой базовый элемент управления карты был инициализирован с размером поверхности 0 высота, 0 ширина, что является допустимым, но не правильным. Когда я нажал на карту, я вызывал базовый элемент управления карты, чтобы перевести мой щелчок мышью (x, y) в широту, и это вызвало AccessViolationException.

Мое исправление состояло в том, чтобы повторно инициализировать базовый элемент управления картой с новым размером поверхности всякий раз, когда возникает событие UserControl.Resize, которое, по-видимому, надежно происходит непосредственно перед тем, как карта полностью прорисована в своем правильном размере, и сохранять поле bool mapIsInitialized в моем элементе управления WPF, который остается ложным до тех пор, пока карта не будет инициализирована с ненулевым размером поверхности, будут настроены правильные проекции и карта полностью раскрашена в первый раз. И мои функции (например, преобразование экранных точек в широты), обращающиеся к базовому элементу управления картой, теперь ничего не делают, если mapIsInitialized.

Таким образом, у вас может возникнуть или не возникнуть аналогичная проблема, но я бы попытался обойти код инициализации и посмотреть значения аргументов, которые передаются в базовый элемент управления картой, чтобы увидеть, имеют ли они смысл, и если инициализация происходит, как вы ожидаете, с правильными значениями в нужное время.

Удачи!

...