以下组件类型有两个实例:
TfrmTimeSliceStructure
,是TFrame
的直系后裔。THKSDBVirtualStringTree
,它是TDBVirtualStringTree
(来自FIBPlus(的直系后裔,而本身就是迈克·利施克TVirtualStringTree
类的直系后裔。
THKSDBVirtualStringTree
组件用作TfrmTimeSliceStructure
上的子控件。
双击 - 在某些情况下 - 框架将被破坏。
为此,我使用自定义消息代码WM_USER + 4
(这是十六进制$0404
(进行PostMessage
调用,以便延迟销毁,直到完全处理所有当前消息。
但是,在许多情况下会发生访问冲突,因为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)
该问题是由显式调用Application.ProcessMessages
OnNodeDblClick
事件处理程序代码中的某个位置引起的。
不幸的是,我们的代码库中仍然有一些这样的调用。
让我告诉你我是如何发现问题的原因的:
正如您在问题中看到的,我尝试了以下两种方法:
- 覆盖控件的
WndProc
,并使用OutputDebugString
记录每条已处理的消息。 - 检查控件是否已销毁,方法是将一个对
OutputDebugString
的调用添加到控件析构函数的开头,将另一个调用添加到控件析构函数的末尾。
后来,我想到了...
- ...检查启动用户交互(此处:双击(是否已完全处理。这也要用
OutputDebugString
来完成。
就我而言,在发生访问冲突之前,第二次鼠标按下并未完全处理。
然后我可以得出结论,消息队列在某个地方过早地被处理了。所以,我必须找出Application.ProcessMessages
叫在哪里。
- 因此,我在此方法中添加了一个断点。因为正常的断点会中断消息处理。我使用了另一种断点类型,我必须承认 - 我第一次使用过。
在断点的高级设置中,我取消选择了"中断",而是选择了"日志调用堆栈"。我决定只记录两个堆栈帧,因为我只想知道谁是Application.ProcessMessages
的直接调用者。
经过另一轮重现,我有一个广泛的调试器日志,其中包含每次调用鼠标按下处理程序、对象的析构函数和每次调用Application.ProcessMessages
的所有处理的消息代码和行。
- 现在,我可以推断,在未完成的鼠标按下处理程序开始之后和接收自定义事件
WM_USER + 4
之前,对Application.ProcessMessages
的第一次调用必须是破坏代码的调用。