注册 登录
编程论坛 VFP论坛

请教可以检测到Messagebox()在运行吗?

wxzd123 发布于 2023-05-14 10:08, 537 次点击
可以检测Messagebox()对话框在运行,可以用代码清除吗?谢谢
47 回复
#2
吹水佬2023-05-14 10:26
要看是什么 message box
#3
sdta2023-05-14 10:29
MESSAGEBOX(eMessageText [, nDialogBoxType ][, cTitleBarText][, nTimeout])
看下第4个参数
#4
csyx2023-05-14 10:30
想啥呢?MessageBox 是模式的,显示后就停在哪等待你选择,关未闭前不会执行你的后续代码,就算你知道咋检测,你准备把检查代码放哪?
除非:1) 多进程/多线程协同 or 2) 定时器轮询
就为这多一个进程或线程,或纯属浪费资源的轮询,值得吗?
一定要的话,可以试试 FindWindow - 类名 #32770,找到后发送关闭消息。先斟酌下是否有必要这么做
#5
wxzd1232023-05-14 10:53
回复 2楼 吹水佬
您好,就是直接运行Messagebox()呀
#6
wxzd1232023-05-14 10:54
回复 3楼 sdta
您好,这个方法,不知道为什么跑到表单后面去里
#7
wxzd1232023-05-14 10:55
回复 4楼 csyx
您好,通过另一台机器端口发信息去检测
#8
吹水佬2023-05-14 11:38
以下是引用wxzd123在2023-5-14 10:53:40的发言:

您好,就是直接运行Messagebox()呀


以下是引用wxzd123在2023-5-14 10:55:56的发言:

您好,通过另一台机器端口发信息去检测


看来不只是直接运行Messagebox的问题
详细操作过程说说
#9
sdta2023-05-14 11:51
以下是引用wxzd123在2023-5-14 10:54:44的发言:

您好,这个方法,不知道为什么跑到表单后面去里

是不是你的表单设置问题
#10
foxfans2023-05-14 12:51
可能是调用第三方弹窗,自己写的完全可以把代码屏蔽也就没有清除一说了,外部第三方要么破解nop去掉,要么挂勾子屏蔽即可.
#11
csyx2023-05-14 13:11
以下是引用wxzd123在2023-5-14 10:55:56的发言:
通过另一台机器端口发信息去检测

你这是要远程控制吗,上位机控制下位机?
那么首先你得完成上/下位机之间通讯的事儿,兴许这才是关键,下位机上需要有一个监听或服务进程,在收到/检测到指令后,查找并关闭 MessageBox 对话框
查找对话框窗口的方法我上面已提过不再赘述,找到后给窗口 PostMessage WM_CLOSE 消息即可
#12
wxzd1232023-05-14 14:46
谢谢各位老师
表单WindowType = 0  有书写控件MSINKAUT.InkPicture.1
对话框代码在类里
If Messagebox("您是否把书写结果更新?",36,"信息提示")<>6
可以显示在表单前,当
If Messagebox("您是否把书写结果更新?",36,"信息提示",5000)<>6  时就在表单后面。
#13
csyx2023-05-14 14:49
36+4096 试试
#14
wxzd1232023-05-14 14:58
回复 13楼 csyx
您好,谢谢,显示前面了,说明这没有这个
#15
kangss2023-05-14 15:22
以下是引用wxzd123在2023-5-14 14:46:05的发言:

谢谢各位老师
表单WindowType = 0  有书写控件MSINKAUT.InkPicture.1
对话框代码在类里
If Messagebox("您是否把书写结果更新?",36,"信息提示")<>6
可以显示在表单前,当
If Messagebox("您是否把书写结果更新?",36,"信息提示",5000)<>6  时就在表单后面。

你说的这个现象:messagebox 跑到 表单后面,模式表单跑到另外一个模式表单的后面,导致无法操作的现象,极大的可能是:exe 隐藏了 _screen 导致的副作用,也可能是 MS 的BUG
有人遇到相同的现象,我也遇到了:https://bbs.

_screen 隐藏后的模式表单一般不要超过3层,否则就容易出现这个现象:第3层模式表单跑到第2层后面,messagebox 跑到第三层表单后面
#16
kangss2023-05-14 15:25
刚刚说的这个现象:+4096,也就是 +0x1000 同样无效。
按理说,任何时候 messagebox 都不应该在表单的后面。
#17
sdta2023-05-14 15:45
上传表单上来看看
#18
吹水佬2023-05-14 17:28
问题解决了吗?
没看明是什么问题
#19
wxzd1232023-05-14 19:22
+4096后对话框就在表单前面了,至于为什么不知道
#20
吹水佬2023-05-14 20:45
以下是引用wxzd123在2023-5-14 19:22:02的发言:

+4096后对话框就在表单前面了,至于为什么不知道

4096(0x1000)消息对话框具有WS_EX_TOPMOST样式
试试:
8192(0x2000)禁用当前线程的所有顶层窗口
#21
csyx2023-05-14 20:57
样式有很多种,一种不行就尝试各种组合
程序代码:
#define MB_APPLMODAL                0
#define MB_SYSTEMMODAL              0x1000
#define MB_TASKMODAL                0x2000
#define MB_NOFOCUS                  0x8000
#define MB_SETFOREGROUND            0x10000
#define MB_DEFAULT_DESKTOP_ONLY     0x20000
#define MB_TOPMOST                  0x40000
#22
wxzd1232023-05-15 06:37
回复 20楼 吹水佬
版主你好,8192对话框跑到后面去了
#23
吹水佬2023-05-15 08:43
以下是引用wxzd123在2023-5-15 06:37:34的发言:

版主你好,8192对话框跑到后面去了

未遇到过messagebox跑到后面而出不来的情况。
给个能令messagebox跑到后面去的示例测试一下。
#24
wxzd1232023-05-15 14:23
吹水佬、sdta二位版主您看看什么原因?
只有本站会员才能查看附件,请 登录
#25
foxfans2023-05-15 14:41
自己都设置成alwaysontop=.t. 总是置顶....,.

[此贴子已经被作者于2023-5-15 15:02编辑过]

#26
sdta2023-05-15 14:48
以下是引用wxzd123在2023-5-15 14:23:36的发言:

吹水佬、sdta二位版主您看看什么原因?

9楼已经给出了大致的范围,表单设置问题。
#27
吹水佬2023-05-15 16:01
绕了几圈才搞清楚是什么问题。
#28
csyx2023-05-15 16:29
以下是引用foxfans在2023-5-15 14:41:30的发言:

自己都设置成alwaysontop=.t. 总是置顶....,.

这不是理由,不带 Timeout 参数的 MessageBox 就能置前显示,带上就不一定,说明这就 vfp 的 MessageBox 存在 bug
win32 的 MessageBox api 第一个参数就用于指定宿主窗口的句柄,宿主窗口发出的 MessageBox 应该阻塞其进程的特定消息处理直到关闭对话框,显然 vfp 在带上 Timeout 时不是这样,表现形式就是不带超时参数时,你无法通过点击表单内任意区域激活窗口,必须关闭对话框后才行,而带上超时参数后,就可以随意切换激活,不管你的表单是否 AlwaysOntop 都这样,违反了 MessageBox 的本意

换句话说,从操作系统的角度来看,带超时参数的 MessageBox 是非模式的,不再是原本意义上的模式对话框。而 vfp 却没意识到,仍把它当做模式窗口处理,在关闭之前不执行其后的代码,显然与操作系统对窗口的处理相矛盾

[此贴子已经被作者于2023-5-15 16:49编辑过]

#29
wxzd1232023-05-15 16:50
谢谢各位老师
#30
foxfans2023-05-15 17:05
其实并不存在bug,Vfp的MessageBox实际是对二个API函数的封装MessageBoxA和MessageBoxTimeoutA,
置顶状态时,MessageBoxA时抢占获得焦点只要不被其他置顶窗口激活Messagebox窗口就默认置顶在上面.
而当MessageBoxTimeoutA时,Vfp主窗口本身重绘又置顶就会把messageboxtimeout(本身不置顶)窗口置后,这时候你再弄个置顶窗口放在你主程序上面一样把Vfp主程序统统覆盖,除非你这时候Hook掉这个Messaageboxtimeout窗口,把这个窗口也设置成置顶状态,就会在你的主窗口上面,换句话说,即使你的messagebox置顶别人的也是置顶属性的窗口后激活在你messagebox窗口位置时,一样会在你messagebox窗口之上.

[此贴子已经被作者于2023-5-15 17:20编辑过]

#31
csyx2023-05-15 17:44
以下是引用foxfans在2023-5-15 17:05:56的发言:
其实并不存在bug,Vfp的MessageBox实际是对二个API函数的封装MessageBoxA和MessageBoxTimeoutA,
置顶状态时,MessageBoxA时抢占获得焦点只要不被其他置顶窗口激活Messagebox窗口就默认置顶在上面.
而当MessageBoxTimeoutA时,Vfp主窗口本身重绘又置顶就会把messageboxtimeout(本身不置顶)窗口置后,这时候你再弄个置顶窗口放在你主程序上面一样把Vfp主程序统统覆盖,除非你这时候Hook掉这个Messaageboxtimeout窗口,把这个窗口也设置成置顶状态,就会在你的主窗口上面,换句话说,即使你的messagebox置顶别人的也是置顶属性的窗口后激活在你messagebox窗口位置时,一样会在你messagebox窗口之上.

好吧,请您解释下为何直接调用这个 api 不会发生楼主的情况,原因是什么?

*!*    Messagebox("在这里呀!",1,"信息提示")
Declare Long MessageBoxTimeout in win32api ;
    Long hWnd, String lpText, String lpCaption, Long uType, Long wLanguageId, Long dwMilliseconds
MessageBoxTimeout(Thisform.HWnd, '在这里呀!', '信息提示', 0, 0, 5000)
#32
吹水佬2023-05-15 17:52
个人理解,这样试试:
Messagebox("猫猫躲我",1,"信息提示") 时,表单是不活动的,不响应消息,AlwaysOnTop失效。
Messagebox("我躲猫猫",1,"信息提示",50000) 时,表单是活动的,AlwaysOnTop有效,会响应消息,只是先放在消息队列,等Messagebox返回断续执行。
可以试试继续点击“我躲猫猫”或点击关闭表单看看


[此贴子已经被作者于2023-5-15 19:31编辑过]

#33
吹水佬2023-05-15 17:55
以下是引用csyx在2023-5-15 17:44:51的发言:


好吧,请您解释下为何直接调用这个 api 不会发生楼主的情况,原因是什么?

*!*    Messagebox("在这里呀!",1,"信息提示")
Declare Long MessageBoxTimeout in win32api ;
    Long hWnd, String lpText, String lpCaption, Long uType, Long wLanguageId, Long dwMilliseconds
MessageBoxTimeout(Thisform.HWnd, '在这里呀!', '信息提示', 0, 0, 5000)

可能与Thisform.HWnd(MessageBox的所有者)有关
VFP的MessageBox所有者是不是NULL?还是 _vfp或_screen
#34
吹水佬2023-05-15 17:58
MessageBoxTimeout 虽然在 user32.dll 里,好像是未公开的API,使用时是否会带有不确定性的问题?
只有本站会员才能查看附件,请 登录

#35
foxfans2023-05-15 18:10
刚才看了messagebox和timeout出来的时候还是置顶状态
但传的hwnd不是thisform.hwnd,如果是_screen.hwnd 或_vfp.whnd按上面的例子也不像,会卡在那里和自带的messagebox状态不一样.应该是别的窗口句柄.谁有空可以去enum窗口出来,再一个个比对一下,或直接勾子OD跟看一下是哪个hwnd和enum的对比一下,确认是哪个

[此贴子已经被作者于2023-5-15 18:13编辑过]

#36
csyx2023-05-15 18:20
28楼的时候我说了,怀疑是vfp传递的第一个参数错误,所以我说这是bug
传入的是什么不知道,既不是 Null,也不是 _Screen.hWnd,这俩的光标都是忙状态,与带 timeout 参数时表象不同
#37
csyx2023-05-15 18:41
其实这都不重要,知道 vfp 的 MessageBox 有这毛病就行

我的代码多年前就不直接用这个函数了,全改用自己的 MsgBox,都是直接调用 api
如果指定了超时参数,咱就用 MessageBoxTimeoutW,没有就调 MessageBoxW - 文字或标题是 N' 开头(源于 SQL Server 的 unicode 表示法),就直接传递,不是就先转 unicode
#38
foxfans2023-05-15 19:26
通过勾子可以确定,上面的例子vfp在调用messagebox带时间参数时, Vfp调用 MessageBoxTimeoutA 时里面传的Hwnd 100%是0
只有本站会员才能查看附件,请 登录

上面的例子给messageboxtimeoutA发送的参数如上图
,进一步研究发现,MessageboxA MessageBoxTimeoutA最终都会调用到MessageBoxTimeoutW  ->>    MessageBoxWorker 所以在这下面勾也一样.

[此贴子已经被作者于2023-5-15 20:15编辑过]

#39
吹水佬2023-05-15 20:14
继续试试:
Messagebox("猫猫躲我",1,"信息提示") 时,窗口样式:
  标准样式:0x94C801C5
  扩展样式:0x00010109

Messagebox("我躲猫猫",1,"信息提示",50000) 时,窗口样式:
  标准样式:0x94C801C5
  扩展样式:0x00010101
  
差别在扩展样式,没有Timeout的多了个:
  WS_EX_TOPMOST equ 8h

这正符合有Timeout时 +4096 的做法:MB_SYSTEMMODAL 0x1000(4096)消息对话框具有WS_EX_TOPMOST样式。
#40
foxfans2023-05-15 20:36
对还是按文档,规范参数timeout文档配用参数也是4096,肯定有他的道理.
只有本站会员才能查看附件,请 登录

MessageBox消息经过的函数很多,非常复杂,实在不行就换api不用自带的好控制,4096去alwaysontop也是可以不知道为什么非要ontop


[此贴子已经被作者于2023-5-15 20:40编辑过]

#41
csyx2023-05-15 20:37
我印象中 +4096 时,vfp 创建的对话框是基本样式不一样,增加了一个 DS 开头的对话框样式,具体值忘了,跟设置前景窗口有关
#42
吹水佬2023-05-15 21:37
用 GetWindow(hWnd, GW_OWNER) 获取所有者窗口,没有Timeout的得到的是表单的hWnd,有Timeout的返回0
#43
foxfans2023-05-15 21:42
MessageBox不简单,带时间的那个感觉也做了很多处理,暂时不研究了
只有本站会员才能查看附件,请 登录

#44
csyx2023-05-15 21:48
三种情况下的窗口样式:
不带 timeout 的 MessageBox
只有本站会员才能查看附件,请 登录

带 timeout + 4096 的 MessageBox
只有本站会员才能查看附件,请 登录

用 MessageBoxTimeout api 的
只有本站会员才能查看附件,请 登录


很明显,vfp 的 +4096 不是简单调用 MessageBoxTimeout api

[此贴子已经被作者于2023-5-15 21:51编辑过]

#45
foxfans2023-05-15 21:57
要深入了解原理,看来还是得OD跟进去,或者把相关的样式设置参数修改变化情况勾出来保存后进一步分析观察.
#46
tigerpub2023-05-16 13:06
回复 43楼 foxfans
老鸟
#47
吹水佬2023-05-16 14:52
看来使用 MESSAGEBOX 的 Timeout 还是要多考虑一下,不只是出现在表单上面还是在下面的问题。
消息对话框没有“所有者”,对其他窗口没有什么限制,有可能出现意想不到的结果。
这种情况,消息对话框出现后,用户对窗口的操作虽然没有即时响应,但还是有效的。
如果消息对话框的内容非常重要,用户操作又没得到即时反映,有可能会影响下一歩操作的正确性。
所以重要的提示最好不要用带Timeout的MESSAGEBOX。
#48
吹水佬2023-05-16 14:57
VFP带Timeout的MESSAGEBOX可能是WAIT TIMEOUT 的另一个版本
1