前一段时间,做一个程序,需要完成一个小功能,即对鼠标监视,当左键单击某个文件选中时,获得该文件文件名称。
折腾了好久,最终在windowsXP下完美实现了。实现的思路是:
1、下鼠标钩子,获得鼠标左键clickup事件。
2、使用FindPointWindow,获得鼠标位置窗口句柄。
3、使用SendMessage,向该窗口(SysListView32)发送信息,获得选中文件序号及文件名称。
该程序在WindowsXP下运行正常,可以正确取出文件名。在Windows7和Server2008的桌面(也是SysListView32)也工作正常。
但是windows7和Server2008的文件浏览窗口时DirectUI,无法使用SendMessage获得相应信息。

针对DirectUI,改用IAccessible接口遍历并获得指定句柄的窗口内鼠标选中的文件。
程序getCurrentFileName,入口是指定窗口的句柄。
但是很奇怪,该程序如果从程序本身的窗体上获得句柄参数,能正常执行,找到选中文件(如从一个textbox中获得句柄值)。但是如果是用鼠标钩子和FindPointWindow获得窗口句柄值,自动调用getCurrentFileName,就无法找到选中的文件。
通过调试,可以看到AccessibleObjectFromWindow这句在两种情况下执行结果不一样。
但是不知道原因在哪里?不知道大家有没有对IAccessible接口熟悉的,帮忙分析一下?
程序如下:

#Region "使用IAccessible读取被选中的文件名称(通用于SysListView32和DirectUI两种控件)"
    ''' <summary>
    ''' 从Windows系统窗口中读取被选中的文件名称,需要考虑两种控件。
    ''' 第一种是SyslistView32,WindowsXp桌面和文件浏览窗口,Windows7、Server2008的桌面都是这种控件
    '''         syslistView32控件本身的Role值为33【列表】,每个文件Role值为34【列表项目】,ObjectType为Simple Element
    ''' 第二种是DirectUI,Windows7、Server2008的文件浏览窗口都是这种控件
    '''         DirectUI控件本身内部较为复杂,文件浏览窗口处于DirectUI较深的层次,文件浏览窗口Role值为33【列表】,每个文件Role值为34【列表项目】
    '''         但是特别注意,这里的文件的ObjectType为Container。
    ''' 两种控件都可以使用IAccessible自动化接口取访问,并且层层深入的遍历。但是特别注意,IAccessible不能进入ObjectType为Simple Element的层。
    ''' 也就是说使用IAccessible不能用AccessibleChildren进入SyslistView32的子层取遍历控件,这样会报错。这可能是自己对IAccessible接口工作原理还不是很清楚而导致的。
    ''' 
    ''' 注:这两种控件可以使用工具AccExplore进行研究和查看。
    ''' 
        Private Declare Function AccessibleObjectFromWindow Lib "oleacc" ( _
       ByVal Hwnd As Int32, _
       ByVal dwId As Int32, _
       ByRef riid As Guid, _
       <MarshalAs(UnmanagedType.IUnknown)> ByRef ppvObject As Object) As Int32
    ''' <summary>
    ''' AccessibleObjectFromWindow用于通过调用IAcessible接口,获得指定句柄为Hwnd的窗口com对象整体,将该对象置于ppvObject中,供用户访问
    ''' AccessibleObjectFromWindow如果获得了正确的Com对象,则返回值为0。如果返回值不为0,则说明获得Com对象过程中出错。
    ''' 特别注意,AccessibleObjectFromWindow只能返回Hwnd句柄指向窗口的顶级窗口。这点在Windows 7下使用最为明显。
    ''' </summary>
    Public Declare Function AccessibleChildren Lib "oleacc" ( _
        ByVal paccContainer As IAccessible, _
        ByVal iChildStart As Integer, _
        ByVal cChildren As Integer, _
         <[Out]()> ByVal rgvarChildren() As Object, _
         ByRef pcObtained As Integer) As UInt32
    ''' <summary>
    ''' AccessibleChildren用于获得当前Object即paccContainer的子Object,存放在cChildren集中
    ''' 公用变量strCurrentFileName用于返回获得的文件名
    ''' </summary>
    Public strCurrentFileName As String
    Public Sub getCurrentFileName(ByVal hwndCurrent As Int32)
        Try             
            Dim IACurrent As Accessibility.IAccessible = Nothing
            Dim ID As Int32 = 0
            Dim IID_IAcce As Guid = New Guid("618736E0-3C3D-11CF-810C-00AA00389B71")

'调用AccessibleObjectFromWindow,获得句柄hwndCurrent指向的鼠标当前窗口所在的顶级窗口,放入IACurrent,供访问者使用
            Dim aaVal As Int32 = AccessibleObjectFromWindow(hwndCurrent, ID, IID_IAcce, IACurrent)

'IACurrent = DirectCast(IACurrent.accParent, Accessibility.IAccessible) '不运行这条语句可以根据句柄正确获得child的数量和名称。
            Dim _ChildCount As Integer = IACurrent.accChildCount
            Dim _Children As Object() = New Object(_ChildCount) {}
            Dim _out As Integer
            '调用AccessibleChildren函数,获得当前顶级窗口(特别注意不一定是hwndCurrent所指向的窗口)的第一层子项,放入_Children
            AccessibleChildren(IACurrent, 0, _ChildCount, _Children, _out)
            '对第一层子项进行遍历
            For Each _child As Accessibility.IAccessible In _Children
                '在遍历过程中,会出现取到空子项的情况,如果取到空子项,下面程序会出错,所以需要将空子项排除
                If _child IsNot Nothing Then

'首先判断子项的Role值,33为【列表】,文件为34【列表项目】,我们需要找到33【列表】
                    Dim _accRole As String = _child.accRole(0)          '取当前遍历到的子项的Role
                    '如果控件是SysListView32,则:
                    '1、不能使用Accessibility.IAccessible进入SysListView32的子项
                    '2、可以使用_child.accName(i)、_chile.accState(i)、遍历该"33"列表的子项
                    '3、可以使用 _child.accSelection返回该该"33"列表中被选中的子项,但是该返回值与所期望的值不同。
                    If _accRole = "33" And strListViewClass = "SysListView32" Then
                        '找到列表后,判断当前列表是否有子项被选中。
                        PDMMainForm.LFind33.Text = "找到列表33,名称为" & _child.accName(0)
                        '如果有子项被选中, _child.accSelection返回被选中的值(该值一定大于零), 否则返回空
                        Dim _accSelected As String = _child.accSelection
                        If _accSelected > 0 Then
                            Dim i As Integer
                            i = CInt(_accSelected)
                            strCurrentFileName = _child.accName(i)
                            PDMMainForm.Lfindfile.Text = "找到选中文件,名称为" & strCurrentFileName

Exit Sub
                        End If
                    End If
                    '判断当前子项_child是否还有下一层子项(_child.accChildCount>0),如果有,则进行遍历
                    Dim _accCount As String = _child.accChildCount      '取当前遍历到的子项的子项数量
                    If _child.accChildCount > 0 Then
                        enumchild(_child, _child.accChildCount)
                    End If
                End If
            Next
        Catch
            '如果没有正确获得被选中的文件名称,则屏蔽try语句,进行调试
        End Try
    End Sub
    Sub enumchild(ByVal objParent As Accessibility.IAccessible, ByVal _ChildCount As Integer)
        '遍历二级及二级以下所有子控件,寻找Role为34的子控件
        Dim _accChildren As Object() = New Object(_ChildCount) {}
        Dim _out As Integer
        Try
            AccessibleChildren(objParent, 0, _ChildCount, _accChildren, _out)
        Catch
        End Try

'遍历第n层控件
        Dim istep As Integer = 0
        Try
            '在遍历过程中,如果_accChildren为simple Element,则下面语句会报错,使用try语句避免
            For Each _child As Accessibility.IAccessible In _accChildren
                istep = 1
                '在遍历过程中,会出现取到空子项的情况,如果取到空子项,下面程序会出错,所以需要将空子项排除
                If _child IsNot Nothing Then
                    istep = 2
                    '首先判断子项的Role值,33为【列表】,文件为34【列表项目】,我们需要找到33【列表】
                    Dim _accRole As String = _child.accRole(0)          '取当前遍历到的子项的Role
                    istep = 3
                    If _accRole = "34" Then
                        PDMMainForm.LFind33.Text = "找到列表项34,名称为" & _child.accName(0)
                        Dim _accState As Object = _child.accState(0)
                        Const SYSTEM_MOUSEON As UInt32 = 2     ' 对象被Selection的掩码,参考oleacc.h
                        Dim iMouseOn As UInt32 = _accState And SYSTEM_MOUSEON
                        If iMouseOn = 2 Then
                            strCurrentFileName = _child.accName(0)
                            PDMMainForm.Lfindfile.Text = "找到选中文件,名称为" & strCurrentFileName
                        End If
                        With PDMMainForm.CB33list
                            .Items.Add(_child.accName(0) & "," & _accState & "," & iMouseOn)
                        End With
                    End If
                    
                    Dim _accCount As String = _child.accChildCount      '取当前遍历到的子项的子项数量
                    If _accCount > 0 Then
                        enumchild(_child, _accCount)
                    End If
                End If

Next
        Catch
        End Try
    End Sub

使用IAccessible接口,遍历DirectUI窗口控件的问题?相关推荐

  1. 查找标题已知的窗口句柄,遍历窗口控件句柄

    有了回调函数的概念及上面的例子,我们可以继续了.其实想要找到一个标题已知的窗口句柄,用一个API函数就可以了:FindWindow. 其函数原形是: function FindWindow(lpCla ...

  2. QT 基础知识一(QT安装、创建项目、常用窗口控件使用、信号与槽机制讲解)

    QT概念 Qt:Qt是一个跨平台的C++框架(C++库),Qt除了支持界面设计(GUI编程),还封装了与网络编程.多线程.数据库连接.视频音频等相关的功能. ctrl 撤销(返回上一步) 市面常见的G ...

  3. 简介子窗口控件(api)

    子窗口控件 壹佰软件开发小组  整理编译   回忆第七章的CHECKER程序.这些程序显示了矩形网格.当您在一个矩形中按下鼠标按键时,该程序就画一个x:如果您再按一次鼠标按键,那么x就消失.虽然这个程 ...

  4. 《Windows程序设计》读书笔九 子窗口控件

    第九章 子窗口控件 子窗口可以作为控制屏幕图形显示,响应用户输入,以及在有重要输入事件的时候通知另一窗口. 标准子窗口控件,按钮,复选框,编辑框,列表框,组合框,文本字符串和滚动条. 可以使用Crea ...

  5. C++ Windows窗口程序:子窗口控件之按钮类button

    Windows窗口程序设计中,按钮.文本编辑框等控件都作为一个子窗口在WM_CREATE事件中创建的.其中按钮类button有多种类型和风格,常见的单选钮.复选钮.分组框也在此类中,见下表: 子窗口控 ...

  6. 【Qt】QStackedWidget:将多个窗口控件放入堆中,每次只显示一个窗口控件

    1.简介 QStackedWidget可以容纳多个窗口控件,每次只显示其中一个.例如:登录页面.各种功能页面等不同时显示的窗口,可以放入QStackedWidget中. 2.demo // 创建三个页 ...

  7. mfc e将控件置于窗口顶层_PyQt5学习笔记04 - QWidget窗口控件基类

    本来这一篇是想写一下怎么使用Qt Designer去设计一个界面的,但是我现在通常都是用代码去直接写界面很少用设计器.因为Qt Designer并不是为了python而写的,所以用起来不是很方便.很多 ...

  8. firefox扩展开发(二):用XUL创建窗口控件

    firefox扩展开发(二):用XUL创建窗口控件 2008-06-11 16:57 1.创建一个简单的窗口 <?xml version="1.0"?> <?xm ...

  9. qpython3可视图形界面_python GUI库图形界面开发之PyQt5窗口控件QWidget详细使用方法...

    QWidget基本介绍 基础窗口控件QWidget类是所有用户界面对象的基类,所有的窗口或者控件都直接或者间接的继承自QWidget类. 窗口坐标系统 PyQt使用统一的坐标系统来定位窗口控件的位置和 ...

最新文章

  1. 与优秀的人在一起,自己也会优秀起来!高质量技术群等你加入!
  2. VTK:图像转结构化点用法实战
  3. MathSystem
  4. html button 自动提交,html+js表单form验证自动提交的2种提交方式button和
  5. char*,wchar_t*,CString和BSTR之间的转换
  6. 华策影视:控股股东、实控人等拟合计减持不超4.01%股份
  7. python3.5以及scrapy,selenium,等 安装
  8. LeetCode(872)——叶子相似的树(JavaScript)
  9. preventDefault, stopPropagation, stopImmediatePropagation 三者的区别
  10. android java语言_android可以用java语言开发吗
  11. java编程规范之java命名规范
  12. mysql修改information_schema表时的错误
  13. 1038 统计同成绩学生
  14. 河北大学计算机学院赵润,影视编导
  15. ajax 更新局部视图,使用Ajax局部更新Razor页面的实例代码
  16. 激光打印机维护保养完全手册
  17. android 加速度计,Android加速度计校准?
  18. Kotlin高仿微信-第58篇-开通VIP
  19. matlab火箭模型,基于Matlab/Simulink的新型火箭建模与仿真平台搭建
  20. 铁匠smith_铁匠的大气散射

热门文章

  1. 今天咱们用Python整一个植物大战僵尸游戏 | 附带源码
  2. 新概念二册 Lesson 18 He often does this!他经常干这种事! ( have的用法)
  3. 7款可以实现 PDF 转换 Word 格式的免费在线工具
  4. 一个让人看了心酸、落泪的故事
  5. 程序员的简历应该这么写!!
  6. JDOJ 3055: Nearest Common Ancestors
  7. Windows中制作傻瓜式安装 Yosemite黑苹果教程。看完你就懂了会了
  8. CIO40: IT人之爬格子码字
  9. 人生, 不求活得完美,但求活得实在
  10. Apache服务器解压版配置(win版)