多线程 – PostMessage在线程中返回“无效窗口句柄”

背景:我正在使用OmniThreadLibrary在后台加载批处理模式ADO存储过程.我打开SP之后通过交换连接做了一些略显狡猾的事情,但这看起来非常可靠.我正在使用PostMessage将消息发送回调用表单,这在我的测试应用程序中有效. Primoz的comms频道为我工作,我正在使用它们进行线程间通信,但对于我们的主应用程序,我试图通过使用标准的PostMessage调用来避免这种依赖,就像我们在app中的其他地方一样.

问题:不幸的是,当我把它放到我们的主应用程序中时,PostMessage调用线程开始失败1400:无效的窗口句柄.

我已经自由地添加了额外的PostMessage调用和日志代码来尝试找到问题,但我现在已经没有想法了.代码是样板:

const WM_PW_ADLQUEUEEMPTY = WM_USER + 11;
...
if PostMessage (OwnerHandle, WM_PW_ADLPROGRESS, QueueID, 10) then
    pwDebugLog ('TADLQueue.Run WM_PW_ADLPROGRESS send to  ' + IntToHex (OwnerHandle, 8) + ' (IsWindow '+BoolToStr(IsWindow(OwnerHandle),true)+')     OK for Queue ' + IntToStr (QueueID))
else
    pwDebugLog ('TADLQueue.Run WM_PW_ADLPROGRESS send to  ' + IntToHex (OwnerHandle, 8) + ' (IsWindow '+BoolToStr(IsWindow(OwnerHandle),true)+') failed for Queue ' + IntToStr (QueueID));

但是一系列电话的日志对我来说并不是很有启发性.请注意,时间之后的四个十六进制数字是来自GetCurrentThreadID的线程ID.

15:41:53.221 1614  TpwAsyncDataLoader.RunQueue WM_PW_ADLPROGRESS send to  00A5110C (IsWindow True)    OK for Queue -6
15:41:53.265 13B4  TADLQueue.Run WM_PW_ADLPROGRESS send to  00A5110C (IsWindow True)     OK for Queue -6
15:41:53.554 13B4  TADLQueueManager.WriteSysErrorMessageToDatabase Postmessage   00A5110C (IsWindow False)  failed with 1400  Invalid window handle

任何人都可以对此有所了解吗?当我看着窗户把手变得无效时,我很困惑,但这就是我的样子.

我能想到的一件事是,我在这里展示的表单不处理消息,而是看到“消息队列已满”失败,而不是看起来像IsWindow(句柄)失败.我该怎么测试呢?

最佳答案
有些情况下会重新创建句柄,最明显的是当您更改窗口标志时.这可能是您的应用程序中发生的事情.

到目前为止我发现的关于重建窗户手柄的所有内容都是来自Allen Bauer的this post,但我肯定会读到Peter Peter写的更详细的内容.不幸的是,我似乎无法找到那一个.

Finally, you need to be aware of cases
where your handle may need to get
recreated. This can happen if the
surrounding form or the parent
component’s handle goes through a
recreate process. Up until more recent
releases of Windows, the only way to
change some window flags was to
destroy the handle and recreate with
new flags in the CreateWindowEx()
call. There are many components that
still do this. You know if you’re in a
recreate situation by checking
(csRecreating in ControlState).

编辑

实际上并不是彼得的帖子,但它可能会给你一些新鲜的想法.

The form will not have a handle until
you show it the first time (unless
something in the form load sequence
request the handle) but the handle is
not destroyed when you hide the form
and unless you do something that
forces the form to recreate the
handle, e.g. change its border style
or border icons, or call RecreateWnd
yourself the handle will stay the
same.

It may not be desirable but it cannot
be avoided, at least not the way
Delphi drag&dock is currently
implemented. When you dock the dragged
form to another form it becomes a
control (with WS_CHILD window style)
and that means that its window handle
has to be destroyed and recreated with
the new style. And destroying the
window handle of a container control
automatically destroys the handles for
all child controls as well.

There is also the fact that the forms
window handle is destroyed and
recreated when you assign to its
Parent property. This also destroys
and recreates the handles for all
controls on the form.

转载注明原文:多线程 – PostMessage在线程中返回“无效窗口句柄” - 代码日志