ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[原创] 【重磅发布】:聚光灯——我的加载宏系列小工具【单元格小工具】之四

  [复制链接]

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-2-2 10:50 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖已被收录到知识树中,索引项:Windows API应用
那么,如何用API得到窗口的句柄呢?
方法有很多:
1、可以通过窗口本身的某些属性(如“类”名,“标题”名等)来查找窗口。这种方法是最常用的。
如FindWindow和FindWindowEx函数,前者可以用来查找顶级窗口,后者比前者功能更多,不仅可以查找顶级窗口,还可以用来查找子窗口。
2、可以通过与其它窗口的关系来确定。
如GetParent、EnumWindow和GetNextWindow。
GetParent:获取一个窗口的父窗口的句柄;
EnumWindow:枚举一个窗口的子窗口的句柄。(它需要有一个处理子窗口句柄的过程相配合)
GetNextWindow:获取一个同级的(即同一个Z序列中的)相邻窗口的句柄,根据参数设置,可以是上一个或是下一个窗口的句柄。

在本主题的应用中,需要用到FindWindow和FindWindowEx。
下面,我们将演示通过FindWindow来获得所插入的UserForm1的窗口句柄。

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-2-2 11:53 | 显示全部楼层
本帖最后由 ggmmlol 于 2018-2-2 18:23 编辑

由于窗口的句柄,就相当于窗口 “终身”的  “身份证号”,所以宜使用全局变量来保存它,并在窗体的初始化事件中自动获取。
为此,我们还需要插入一个公共模块,以定义全局的变量和过程。方法是通过主菜单或鼠标右键菜单选择“插入-模块”,得到“模块1”。
接下来,我们在“模块1”中输入以下代码:
  1. '模块1代码


  2. 'API声明、Type定义、全局命名常数
  3. Declare Function IsWindow Lib "user32" (ByVal hwnd As Long) As Boolean
  4. Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
  5. Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWndParent As Long, ByVal hwndChildAfter As Long, ByVal lpszClass As String, ByVal lpszWindow As String) As Long

  6. '全局变量
  7. Public lHwndUserForm1 As Long


  8. '自定义过程

  9. Sub ShowUserForm1()
  10.     UserForm1.Show 0
  11. End Sub

  12. Sub HideUserform1()
  13.     UserForm1.Hide
  14. End Sub

  15. Sub MsgHwndOfUserForm1()
  16.     lHwndUserForm1 = MyHwnd()
  17.     MsgBox lHwndUserForm1
  18. End Sub

  19. Sub UnloadUserForm1()
  20.     Unload UserForm1
  21. End Sub

  22. Function MyHwnd() As Long
  23.      If Val(Application.Version) < 9 Then
  24.          MyHwnd = FindWindow("ThunderXFrame", "UserForm1") '97
  25.      Else
  26.          MyHwnd = FindWindow("ThunderDFrame", "UserForm1") '2000以上
  27.      End If
  28. End Function
复制代码




评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-2-2 13:08 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
现在,附上本教程相关测试用代码的第一个附件。
步骤01_获取窗体句柄.rar (13.78 KB, 下载次数: 169)


TA的精华主题

TA的得分主题

 楼主| 发表于 2018-2-2 14:07 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
通过运行上面的测试附件,我们可以发现:
1、当在执行ShowUserForm1或HideUserForm1之后,立即执行MsgUserForm1,将显示同一个非零的整数;(这表明,窗体在Show或Hide状态时,都是同一个确定存在的窗口)。
2、而当执行UnloadUserForm1之后再执行MsgUserForm1,将显示“0”;(这表明,这个窗体不存在,或者说其生命周期已经结束)
3、在执行UnloadUserForm1后再执行ShowUserForm1或HideUserForm1,然后执行MsgUserForm1,则显示另一个非零的整数。(这表明,在对窗体进行Unload的前后所分别显示的窗体,即使位置、外形完全一致,但它们并不是同一个窗体对象了。)

于是,为了使全局变量lHwndUserForm1与关联的窗体生命周期一致,也避免每次使用时都需要调用一次FindWindow函数的重复工作,按12楼就已经提到的办法,改为在窗体的初始化事件中获取其句柄到lHwndUserForm1中,而在窗体的终止事件中,使lHwndUserForm1的值归零。

所以,对这两个模块的代码做一些修正:
1、在UserForm1窗体中,添加以下代码:

  1. Private Sub UserForm_Initialize()
  2.     lHwndUserForm1 = MyHwnd()
  3. End Sub

  4. Private Sub UserForm_Terminate()
  5.     lHwndUserForm1 = 0
  6. End Sub
复制代码



2、把模块1的MyHwnd自定义函数也移到UserForm1的代码空间,并做一些调整:用Me.Caption代替"UserForm1",以自动适应对窗体的Caption属性的修改。
修改后的代码如下:
  1. Function MyHwnd() As Long
  2.      If Val(Application.Version) < 9 Then
  3.          MyHwnd = FindWindow("ThunderXFrame", Me.Caption) '97
  4.      Else
  5.          MyHwnd = FindWindow("ThunderDFrame", Me.Caption) '2000以上
  6.      End If
  7. End Function
复制代码



3、对“模块1”中的ShowUserForm1、HideUserForm1、UnloadUserForm1、MsgUserForm1这4个测试用的过程代码,予以删除或注释掉。

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-2-2 14:14 | 显示全部楼层
把经过上述优化的文件另存,得到本教程的第2个 代码测试用的附件:
窗口测试_获取窗体句柄_优化.rar (13.81 KB, 下载次数: 149)

TA的精华主题

TA的得分主题

发表于 2018-2-2 15:13 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-2-2 16:13 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
前面,我们已经能够获取窗体的句柄,这意味着我们可以利用它来大作文章了。
具体到我的这个主题,利用UserForm1的句柄,对它的窗体风格进行修改,使之具有“双透明特征”。
这就要用到GetWindowLong、SetWindowLong,以及SetLayeredWindowAttributes 这三个函数,分别用于获取和修改窗体的风格特征。
同时,这两个函数使用一些命名常量做为参数,以便于编写和阅读代码。这些,也与上面的函数一道,而作为外部引用的申明,加入到“模块1”的开始部分。
内容如下:
  1. Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
  2.              Private Const GWL_STYLE = (-16)
  3.              Private Const GWL_EXSTYLE = (-20)
  4. Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
  5.              Private Const WS_BORDER = &H800000
  6.              Private Const WS_CAPTION = &HC00000                  '  WS_BORDER Or WS_DLGFRAME
  7.              Private Const WS_CHILD = &H40000000
  8.              Private Const WS_EX_TOOLWINDOW = &H80&
  9.              Private Const WS_EX_TRANSPARENT As Long = &H20&
  10.              Private Const WS_EX_LAYERED = &H80000
  11. Declare Function SetLayeredWindowAttributes Lib "user32" (ByVal hwnd As Long, ByVal crKey As Long, ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long
  12.              Private Const LWA_ALPHA = &H2
  13.              Private Const LWA_COLORKEY = &H1
复制代码



然后,编写自定义过程,调用以上API函数对窗体的风格做修改。
这部分的代码如下:
'模块1的部分代码
  1. Function ModifyWindowStyleEx(ByVal hwnd As Long,  ByVal nIndex As Long, ByVal dwNewLong As Long) as Boolean
  2. dim lStyle as long
  3. lStyle = GetWindowLong(hwnd, nIndex)
  4. lStyle = lStyle or dwNewLong
  5. ModifyWindowStyleEx = SetWindowLong(hwnd, nIndex, lStyle)
  6. End Function
  7. Sub SetWindowTRANSPARENT(ByVal hwnd As Long) '使窗口对鼠标按键透明
  8. ModifyWindowStyleEx hwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT
  9. End Sub
  10. Sub SetWindowLayeredAlpha(ByVal hwnd As Long) '使窗口的整个图形透明(透明程度为40)
  11. ModifyWindowStyleEx hwnd, GWL_EXSTYLE, WS_EX_LAYERED
  12. SetLayeredWindowAttributes hwnd, 0, 40, LWA_ALPHA '(透明程度取值范围:0至255,取0,则全部透明,取255,则全部不透明)
  13. End Sub
复制代码





TA的精华主题

TA的得分主题

 楼主| 发表于 2018-2-2 17:23 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
接下来,就是第3个代码测试附件了。
如果前面2个附件,只是让你闻到少许香味的话,那这第3个附件,可以算得上能够上桌的花式摆盘的开胃菜了。
窗口测试_鼠标穿透的半透明窗体.rar (19.84 KB, 下载次数: 213)

评分

2

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-2-4 11:32 | 显示全部楼层
我们的《窗体“变形记”》第一集已经“播出”,从目前的情况来看,反应寥寥,“收视率”真的很低啊。

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-2-4 11:34 | 显示全部楼层
不纠结了,继续“播出”我们的《窗体“变形记”》的第二集。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-3-29 18:40 , Processed in 0.413023 second(s), 7 queries , Gzip On, Redis On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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