ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: qifenghome

[求助] 如何设置让VBA窗体置顶

[复制链接]

TA的精华主题

TA的得分主题

发表于 2009-5-24 07:28 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖已被收录到知识树中,索引项:窗体
再次认真读这一段:
Return Value  (返回值)
If an application processes this message, it should return zero.
如果应用程序处理此条消息,它应该返回0。(也就是说,如果要屏蔽窗口的WM_INITMENU消息,只需将自定义的窗口消息函数返回值设为0,即代码中的WndProc=0,这样窗口自带的消息处理函数在收到这条消息后就不招待相应的代码了)

是否表示:如果窗口按照自己的过程成功处理此消息,返回值即为0。也就是说:如果返回值为非0,是否该消息还要被自动发送给窗口默认的消息处理函数(即lOldProc 所指的函数)去处理呢?返回0,表示此消息已被处理过了,系统的处理函数就可以休息了,可以不管了?嘿嘿,多半是这样的,这符合windows消息处理机制(对“windows消息处理机制”我不懂,只知道windows就是通过消息处理机制来驱动的)!

TA的精华主题

TA的得分主题

发表于 2009-5-24 07:02 | 显示全部楼层
原帖由 小fisher 于 2009-5-23 23:19 发表

试验了一下,如果不加最大、最小化按钮,只需在窗口的Initialize事件中一次性将关闭按钮禁用即可,如果添加了最大、最小化按钮,窗口在弹出菜单之前会收到WM_INITMENU消息,在这个消息处理程中会重绘菜单,之后关闭 ...


小fisher,太感谢您了,我就说嘛,没有您的指导,我哪能学API哟。
我对API基本上是“盲”,知道的一点儿全是从您那儿学过来的。您上面的代码,我差点没读懂,后来通过搜索,结合这个帖子的注释:
http://club.excelhome.net/thread-306231-1-1.html我总算明白了大部分,下面是我的理解,您看对不对,如有错误,请赐教哟:
1、什么叫子类化?
子类化只是把截取窗口类的过程地址,用自己的窗口过程替代他。(这个我之前在学编程的时候知道一丁点儿,所以不太陌生!)
2、您给的代码是怎样“子类化”的?
第一步:设置新的窗口消息处理函数
Private Function WndProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lparam As Long) As Long
    Select Case Msg
        Case WM_INITMENUPOPUP
            WndProc = 0
        Case Else
            WndProc = CallWindowProc(lOldProc, hwnd, Msg, wParam, lparam)
    End Select
   
End Function

此函数中有两点意思:
(1)当消息为WM_INITMENUPOPUP时,强制返回值为0,按您的意思,表示“不处理”此消息。对吗?
(2)当消息为别的消息时,由原来的窗口函数(系统默认的)去处理它。对吗?


第二步:设置新的窗口函数替代系统默认的处理函数
lOldProc = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf WndProc)
lOldProc 即为系统的默认的窗口(消息)处理函数地址。

有一点儿不明白:
CallWindowProc(lOldProc, hwnd, Msg, wParam, lparam)我大概知道是向窗口发送消息,并传递消息处理函数的地址让它去处理这个消息。我不明白的是:它的返回值是什么?联系上面您讲的,返回0是表示不处理,其它正常返回的值是什么?不同的值表示什么涵义?(不同的值表示不同的处理方法?值与方法对应是什么?不过,这也许是系统内部的事,不该由系统外的人(或函数)来管,是吧?)

总之,谢谢小fisher的精心指导!感激之至,无以言表!

[ 本帖最后由 fdd 于 2009-5-24 07:04 编辑 ]

TA的精华主题

TA的得分主题

发表于 2009-5-23 21:44 | 显示全部楼层
原帖由 小fisher 于 2009-5-23 00:53 发表

下面的代码添加最大、最小化按钮,并且让关闭按钮不可用(在窗口上双击左键关闭)
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As ...



为何在窗体左上角一按右键,出现控件菜单后,关闭按钮就可以用了。为何?小Fisher。

TA的精华主题

TA的得分主题

发表于 2009-5-23 23:19 | 显示全部楼层
原帖由 fdd 于 2009-5-23 21:44 发表



为何在窗体左上角一按右键,出现控件菜单后,关闭按钮就可以用了。为何?小Fisher。

试验了一下,如果不加最大、最小化按钮,只需在窗口的Initialize事件中一次性将关闭按钮禁用即可,如果添加了最大、最小化按钮,窗口在弹出菜单之前会收到WM_INITMENU消息,在这个消息处理程中会重绘菜单,之后关闭按钮就变得可用了。可通过子类化屏蔽WM_INITMENU消息。代码见附件
disableClose.rar (11.03 KB, 下载次数: 189)

TA的精华主题

TA的得分主题

发表于 2009-5-23 23:32 | 显示全部楼层
窗口所收到的消息可以通过Spy++截获,在这里,应该重点关注在窗口标题栏中按下右键时窗口收到的与菜单相关的消息(通常消息名字中带有MENU字样),然后在自定义的窗口函数WndProc中逐个筛选屏蔽,就会找到“罪魁祸首”了,关于窗口消息的具体说明可以参考MSDN,比如WM_INITMENU消息的说明:

WM_INITMENU Message
--------------------------------------------------------------------------------
The WM_INITMENU message is sent when a menu is about to become active. It occurs when the user clicks an item on the menu bar or presses a menu key. This allows the application to modify the menu before it is displayed.
A window receives this message through its WindowProc function.

Syntax (语法)

WM_INITMENU
               
  WPARAM wParam   
  LPARAM lParam   

Parameters(参数)

wParam
Handle to the menu to be initialized.
lParam
This parameter is not used.

Return Value  (返回值)
If an application processes this message, it should return zero.
如果应用程序处理此条消息,它应该返回0。(也就是说,如果要屏蔽窗口的WM_INITMENU消息,只需将自定义的窗口消息函数返回值设为0,即代码中的WndProc=0,这样窗口自带的消息处理函数在收到这条消息后就不招待相应的代码了)

Remarks   (说明)
A WM_INITMENU message is sent only when a menu is first accessed; only one WM_INITMENU message is generated for each access. For example, moving the mouse across several menu items while holding down the button does not generate new messages. WM_INITMENU does not provide information about menu items.
Message Information

TA的精华主题

TA的得分主题

发表于 2009-5-24 13:13 | 显示全部楼层
1、什么叫子类化?
子类化只是把截取窗口类的过程地址,用自己的窗口过程替代他。(这个我之前在学编程的时候知道一丁点儿,所以不太陌生!)

这个说的是子类化的实现方式。子类化的本质应该是对现有的类进行定制,使其在继承原有类大部分特性(外观和行为)的同时增加自己独有的特性(通常是行为),这样的效果是在原来类的基础上衍生出了一个子类。
2的理解正确
3CallWindowProc(lOldProc, hwnd, Msg, wParam, lparam)的返回值根据消息类别、传入的wParam和lParam的不同会不一样,具体要参照MSDN中对于该消息的说明。在自定义的窗口过程中,可以不去关心具体的返回值,把它当成系统内部的事,系统原来怎么处理的,现在还让它怎么处理。
...
是否表示:如果窗口按照自己的过程成功处理此消息,返回值即为0。也就是说:如果返回值为非0,是否该消息还要被自动发送给窗口默认的消息处理函数(即lOldProc 所指的函数)去处理呢?返回0,表示此消息已被处理过了,系统的处理函数就可以休息了,可以不管了?
...

因为有上面MSDN中给出的说明,所以这里让WndProc=0,“表示此消息已被处理过了,系统的处理函数就可以休息了,可以不管了”;其他的情况,最好还是让返回值与lOldProc指向的函数的返回值一致,即WndProc=CallWindowProc(lOldProc, hwnd, Msg, wParam, lparam),而不要去指定为一个具体数值,比如WndProc=1。因为没法保证“如果返回值为非0,该消息要被自动发送给窗口默认的消息处理函数(即lOldProc 所指的函数)去处理”。

[ 本帖最后由 小fisher 于 2009-5-24 13:18 编辑 ]

TA的精华主题

TA的得分主题

发表于 2009-5-24 21:00 | 显示全部楼层
原帖由 小fisher 于 2009-5-24 13:13 发表

这个说的是子类化的实现方式。子类化的本质应该是对现有的类进行定制,使其在继承原有类大部分特性(外观和行为)的同时增加自己独有的特性(通常是行为),这样的效果是在原来类的基础上衍生出了一个子类。
2的理 ...


哦,“子类化”的概念是如此的呀!自己还得努力学才行,谢谢小fisher的回复及讲解。我得一步一步来,至少能掌握这里的代码就是良好的开端。
我还想到:如果在自己的新建的窗口消息处理函数里对所有消息都强制返回0,那必将造成对该窗口被“挂起”(不知道怎么说才好,反正就是对任何消息都不会有反应了),对吧?

[ 本帖最后由 fdd 于 2009-5-24 21:06 编辑 ]

TA的精华主题

TA的得分主题

发表于 2010-6-13 08:34 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2011-7-21 13:00 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助

TA的精华主题

TA的得分主题

发表于 2011-8-20 17:03 | 显示全部楼层
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-12-5 10:27 , Processed in 0.050757 second(s), 8 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表