Нарушение прав доступа при доступе к COM-объекту из .Net - PullRequest
1 голос
/ 15 марта 2009

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

1. Исключение «нарушение прав доступа» уничтожает мое управляемое приложение

Мое приложение C # WinForms иногда закрывается с исключением «Нарушение прав доступа» («Попытка чтения или записи в защищенную память»), прямо в момент выбора TabPage в форме окна TabControl. Из трассировки стека (попробуйте / поймайте вокруг Application.Run) я вижу, что исключение происходит в System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg), вызывается внутри UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData).

-- Message: Attempted to read or write protected memory.
   This is often an indication that other memory is corrupt.
-- Stack trace:
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager
      .System.Windows.Forms.UnsafeNativeMethods
      .IMsoComponentManager.FPushMessageLoop
      (Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext
      .RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext
      .RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(ApplicationContext context)
   at MyApp.Program.Main()

2. Кажущийся неисправным модуль является COM-объектом (ChartFX Client Server 6.2)

Используя WinDbg (с загруженным SoS), я обнаружил его на неуправляемой стороне, внутри ChartFX.ClientServer.Core.dll (это используемый нами компонент построения диаграмм COM):

(ca84.c98c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=06e67c38 ecx=06e67c38 edx=000018c6 esi=06e7df30 edi=317a9e80
eip=31666110 esp=0015e040 ebp=0015e08c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
ChartFX_ClientServer_Core!Ordinal5507+0x97b7:
31666110 8a404d          mov     al,byte ptr [eax+4Dh]      ds:0023:0000004d=??

[править:] Я также не смог получить информацию о неповрежденном стеке из WinDbg (там говорилось: «Информация о размотке стека недоступна»):

0:000> kP
ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
0015e08c 3166288b ChartFX_ClientServer_Core!Ordinal5507+0x97b7
0015e394 3165a921 ChartFX_ClientServer_Core!Ordinal5507+0x5f32
0015e480 31678685 ChartFX_ClientServer_Core!Ordinal5496+0x26a
0015e568 3167bef4 ChartFX_ClientServer_Core!Ordinal5492+0x975
0015e668 316a356b ChartFX_ClientServer_Core!Ordinal5492+0x41e4
0015e77c 31709496 ChartFX_ClientServer_Core!Ordinal443+0x5745
0015e7d0 31707f70 ChartFX_ClientServer_Core!Ordinal2584+0x3cdc
0015e7f8 3170817d ChartFX_ClientServer_Core!Ordinal2584+0x27b6
0015e81c 3162fd76 ChartFX_ClientServer_Core!Ordinal2584+0x29c3
0015e86c 7719f8d2 ChartFX_ClientServer_Core!Ordinal899+0x6b6
0015e898 7719f794 USER32!GetMessageW+0x93
0015e910 771a06f6 USER32!GetWindowLongW+0x115
0015e940 771a069c USER32!CallWindowProcW+0x75
0015e960 747fcef4 USER32!CallWindowProcW+0x1b
0015e97c 747fd073 comctl32!Ordinal377+0x5c
0015e9e0 747fd027 comctl32!DefSubclassProc+0x92
0015ea04 747fd4e6 comctl32!DefSubclassProc+0x46
0015ea20 747fd073 comctl32!DefSubclassProc+0x505
0015ea84 747fd118 comctl32!DefSubclassProc+0x92
0015eae4 7719f8d2 comctl32!DefSubclassProc+0x137

3. Ошибка не легко воспроизвести (хотя ее можно спровоцировать обычно менее чем за 5 минут)

У меня есть несколько экземпляров Chart на нескольких вкладках, и это обычно происходит, когда я переключаю вкладки. Я до сих пор не знаю, как воспроизвести его, кроме переключения этих вкладок на несколько минут, прежде чем это произойдет, поэтому я не могу использовать наш источник контроля, чтобы надежно найти сборку, у которой не было этой проблемы. Я получаю доступ к диаграммам через управляемый класс-оболочку AxChart (производный от AxHost), который был автоматически создан дизайнером VS.

4. Каким должен быть мой следующий шаг?

Если бы кто-то мог указать мне на следующий шаг, который я должен сделать, чтобы найти истинную причину, я был бы очень благодарен. Экспериментирование (удаление и возврат кода) не приносит пользы, потому что я не знаю, как его воспроизвести, поэтому на каждую итерацию уйдет много времени, чтобы убедить себя в том, что ошибка все еще существует.

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

Заранее большое спасибо!

С уважением, Гру

Ответы [ 3 ]

2 голосов
/ 19 марта 2009

Добавляя множество трассировок журнала по всему коду, мне удалось заметить, что в некоторых случаях одно из свойств диаграммы превращается в Double.NaN. После этого приложение всегда зависало при следующей перерисовке диаграммы. Обрабатывая события Chart PrePaint и PostPaint (к счастью, у них есть эти события), я подтвердил, что сбой происходит прямо между этими двумя событиями.

В частности, это происходит только в том случае, если я установил масштаб графика до того, как он был нарисован впервые (впервые после последнего обновления). Мне удалось сделать это по-другому, и с тех пор он не разбился.

Я не очень доволен этим «решением», поскольку это, очевидно, какая-то внутренняя проблема, которая не может быть точно обнаружена до ее фактического сбоя, и я, возможно, только скрываю ее таким образом. Но я должен оставить все как есть, потому что иначе я теряю слишком много времени.

[Update]

Успешно воспроизведена ошибка

Я выполнил быстрое тестовое приложение, в котором дважды устанавливал свойства некоторой диаграммы, прежде чем она на самом деле была нарисована, и приложение сразу же зависало. Я сообщил об ошибке в Software FX, но не получил ответа. Это не первая раздражающая ошибка, с которой я сталкиваюсь с этим элементом управления, но в следующем выпуске мы переключаемся на их управляемую (.Net) версию, поэтому у нас будет хотя бы Reflector, чтобы выяснить, как устранить эти ошибки.

В любом случае, спасибо всем!

1 голос
/ 16 марта 2009

Это очень похоже на проблему безопасности потока.
Я бы посоветовал вам начать с прочтения документации по элементу управления, обращая особое внимание на упоминание безопасности потоков. Модель потоков, обычно используемая COM-компонентами, отличается - и часто несовместима - с (тривиальным) использованием .NET.

0 голосов
/ 15 марта 2009

Был один из них некоторое время назад. В нашем случае это был вызов PInvoke: OpenPrinter (string port);

Наша проблема заключалась в том, что управляемый код отправил: «LPT1:», но неуправляемый код объявил массив байтов [1024] и прочитал 1024 байта и далее с адреса строки. Это будет считывать за пределами выделенной строки («LPT1:») и иногда попадать в память, которая не была выделена для приложения, вызывая это прерывистое исключение AccessViolationException.

Мы исправили это, изменив вызов на: OpenPrinter (int длина, строковый порт), чтобы неуправляемый код мог объявить байтовый массив правильной длины.

В этом сообщении от ctacke также есть некоторые полезные сведения о том, что может быть причиной этой проблемы.

...