Как предотвратить обработку сообщений после уничтожения элемента управления

Существует два экземпляра следующих типов компонентов:

  1. TfrmTimeSliceStructure, который является прямым потомком TFrame,
  2. THKSDBVirtualStringTree, который является прямым потомком TDBVirtualStringTree (из FIBPlus), который сам является прямым потомком Майка Лишке TVirtualStringTree учебный класс.

THKSDBVirtualStringTree компонент используется в качестве дочернего элемента управления TfrmTimeSliceStructure,

При двойном щелчке - при определенных условиях - рамка будет уничтожена.

Для этого я делаю PostMessage позвонить с пользовательским кодом сообщения WM_USER + 4 (это шестнадцатеричный $0404), так что уничтожение будет отложено до полной обработки всех текущих сообщений.

Хотя во многих случаях происходит нарушение доступа, так как THKSDBVirtualStringTree компонент все еще обрабатывает сообщения после своего уничтожения.

Я ожидал, что после уничтожения элемента управления обработка сообщений не происходит.

Как я могу предотвратить обработку сообщений элементом управления, который уже был уничтожен?

Ниже вы можете увидеть выходные данные отладчика. В обоих классах я добавил запись журнала в метод WndProc вывести полученный код сообщения. В первой строке видно, что мой пользовательский код сообщения WM_USER + 4 был получен.

Несколько строк позже, есть две строки Instance of class THKSDBVirtualStringTree is going to be destroyed. а также Instance of class THKSDBVirtualStringTree has been destroyed., Между этими двумя строками сообщения не принимаются.
После этих строк по-прежнему обрабатываются некоторые сообщения. В конце концов, это приводит к нарушению доступа в конце. Из их кодов сообщений я вижу, что эти сообщения являются управляющими сообщениями, потому что CM_BASE = $B000;,

Debug-Ausgabe: Instance of class TfrmTimeSliceStructure recieved message $0404 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class TfrmTimeSliceStructure recieved message $0405 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class TfrmTimeSliceStructure recieved message $8001 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $0200 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $0202 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $0215 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $02A3 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B014 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class TfrmTimeSliceStructure recieved message $B014 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class TfrmTimeSliceStructure recieved message $8001 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class TfrmTimeSliceStructure recieved message $8001 Prozess Memory.exe (20916)
Thread-Start: Thread-ID: 6260. Prozess Memory.exe (20916)
Thread-Start: Thread-ID: 21148. Prozess Memory.exe (20916)
Thread-Ende: Thread-ID: 6260. Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class TfrmTimeSliceStructure recieved message $0002 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class TfrmTimeSliceStructure recieved message $000E Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $0272 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $0002 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $000E Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $0082 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class TfrmTimeSliceStructure recieved message $0082 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree is going to be destroyed. Prozess Memory.exe (20916)
Thread-Ende: Thread-ID: 22156. Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree has been destroyed. Prozess Memory.exe (20916)
Thread-Start: Thread-ID: 5672. Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B028 Prozess Memory.exe (20916)
Thread-Start: Thread-ID: 9244. Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B009 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B008 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B023 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B03D Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B050 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B058 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B011 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B03B Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B03B Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B00D Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B022 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B009 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B008 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B023 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B035 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B03D Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B050 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B058 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B011 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B009 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B035 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B034 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B009 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B03B Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B008 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B00E Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B034 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B008 Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B00E Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B034 Prozess Memory.exe (20916)
Thread-Ende: Thread-ID: 5672. Prozess Memory.exe (20916)
Thread-Ende: Thread-ID: 21148. Prozess Memory.exe (20916)
Debug-Ausgabe: Instance of class THKSDBVirtualStringTree recieved message $B007 Prozess Memory.exe (20916)
Erste Gelegenheit für Exception bei $01819981. Exception-Klasse $C0000005 mit Meldung 'access violation at 0x01819981: read of address 0x00000050'. Prozess Memory.exe (20916)

1 ответ

Решение

Проблема была вызвана явным вызовом Application.ProcessMessages где-то в нашем OnNodeDblClick код обработчика события.

К сожалению, у нас все еще есть некоторые из этих вызовов в нашей кодовой базе.:-(


Позвольте мне рассказать вам, как я выяснил причину проблемы:

Как вы можете видеть в вопросе, я попробовал эти два подхода:

  1. Переопределить контроль WndProc и регистрируйте каждое обработанное сообщение OutputDebugString,
  2. Проверьте, был ли элемент управления уже уничтожен, добавив один вызов OutputDebugString в начале, а другой в конец вашего деструктора управления.

Позже мне пришло в голову...

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

Тогда я могу заключить, что где-то очередь сообщений обрабатывается преждевременно. Итак, я должен был выяснить, где Application.ProcessMessages называется.

  1. Поэтому я добавил точку останова в этом методе. Потому что нормальная точка останова нарушила бы обработку сообщений. Я использовал другой тип точки останова, который - я должен признаться - я использовал в первый раз вообще.
    В дополнительных настройках точки останова я снял флажок " Разорвать" и вместо этого выбрал " Log Call Stack". Я решил зарегистрировать только два фрейма стека, потому что я просто хотел знать, кто является прямым абонентом Application.ProcessMessages является.

После следующего цикла воспроизведения у меня был обширный журнал отладчика, содержащий все эти обработанные коды сообщений и строки для каждого вызова обработчика нажатия мыши, деструктора объекта и каждого вызова Application.ProcessMessages,

  1. Теперь я могу сделать вывод, что первый звонок Application.ProcessMessages после начала незавершенного обработчика мыши и до получения моего пользовательского события WM_USER + 4 должен быть тот, который нарушает код.
Другие вопросы по тегам