Как предотвратить обработку сообщений после уничтожения элемента управления
Существует два экземпляра следующих типов компонентов:
TfrmTimeSliceStructure
, который является прямым потомкомTFrame
,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
код обработчика события.
К сожалению, у нас все еще есть некоторые из этих вызовов в нашей кодовой базе.:-(
Позвольте мне рассказать вам, как я выяснил причину проблемы:
Как вы можете видеть в вопросе, я попробовал эти два подхода:
- Переопределить контроль
WndProc
и регистрируйте каждое обработанное сообщениеOutputDebugString
, - Проверьте, был ли элемент управления уже уничтожен, добавив один вызов
OutputDebugString
в начале, а другой в конец вашего деструктора управления.
Позже мне пришло в голову...
- ... проверить, полностью ли обработано инициирующее взаимодействие с пользователем (здесь: двойной щелчок). Это должно быть сделано с
OutputDebugString
, тоже.
В моем случае второе нажатие мыши не было полностью обработано до того, как произошло нарушение доступа.
Тогда я могу заключить, что где-то очередь сообщений обрабатывается преждевременно. Итак, я должен был выяснить, где Application.ProcessMessages
называется.
- Поэтому я добавил точку останова в этом методе. Потому что нормальная точка останова нарушила бы обработку сообщений. Я использовал другой тип точки останова, который - я должен признаться - я использовал в первый раз вообще.
В дополнительных настройках точки останова я снял флажок " Разорвать" и вместо этого выбрал " Log Call Stack". Я решил зарегистрировать только два фрейма стека, потому что я просто хотел знать, кто является прямым абонентомApplication.ProcessMessages
является.
После следующего цикла воспроизведения у меня был обширный журнал отладчика, содержащий все эти обработанные коды сообщений и строки для каждого вызова обработчика нажатия мыши, деструктора объекта и каждого вызова Application.ProcessMessages
,
- Теперь я могу сделать вывод, что первый звонок
Application.ProcessMessages
после начала незавершенного обработчика мыши и до получения моего пользовательского событияWM_USER + 4
должен быть тот, который нарушает код.