检测Excel应用程序、工作簿或工作表中的焦点丢失

检测Excel应用程序、工作簿或工作表中的焦点丢失,excel,vba,Excel,Vba,在MS Windows上使用MS Excel时,通过systemALT Tab热键切换到其他应用程序会导致Excel失去键盘焦点。如何检测这个 对象的停用或窗口停用事件:应用程序或工作簿或工作表对象在MS Excel以这种方式失去焦点时不会激发(当然,因为失去焦点并不等同于停用窗口)请尝试此代码。三年前,我在互联网上的某个地方找到了它,它只适合我的需要。例如,它无法停止,因为UnhookWinEventAPI的声明错误。注意不要监视使用MsgBox丢失或获取的焦点。这样,按下“OK”键,焦点将再

在MS Windows上使用MS Excel时,通过system
ALT Tab
热键切换到其他应用程序会导致Excel失去键盘焦点。如何检测这个


对象的
停用
窗口停用
事件:
应用程序
工作簿
工作表
对象在MS Excel以这种方式失去焦点时不会激发(当然,因为失去焦点并不等同于停用窗口)

请尝试此代码。三年前,我在互联网上的某个地方找到了它,它只适合我的需要。例如,它无法停止,因为
UnhookWinEvent
API的声明错误。注意不要监视使用MsgBox丢失或获取的焦点。这样,按下“OK”键,焦点将再次被接收,您将处于无限循环中。焦点状态将在活动工作表中返回,范围为“A1”(接收焦点),分别为“A2”(失去焦点):

  • 复制模块顶部的下一个代码(在声明区域中):
  • 复制模块内的下一个代码:
  • 您必须从
    StartMonitoring
    Sub
    开始监视,该监视可以直接调用,也可以通过事件调用(例如,打开工作簿)


    可以停止监视调用
    StopMonitoring
    Sub
    ..

    这无法使用标准Excel功能完成。任何Excel事件都无法捕获丢失或获取焦点。但它可以使用API来完成
    SetWinEventHook
    可以做到这一点。我(在我电脑的某个地方)有这样一个代码。我不是它的“父亲”,我是从网上某个地方收集的。如果我能找到它,我会发布一个答案,告诉你我是如何使用它的。。。我重复一遍,我没有在讨论中创建代码!
        Option Explicit
        
        Private Const EVENT_SYSTEM_FOREGROUND = &H3&
        Private Const WINEVENT_OUTOFCONTEXT = 0
        
        Private Declare PtrSafe Function SetWinEventHook Lib "user32.dll" (ByVal eventMin As Long, _
                    ByVal eventMax As Long, ByVal hmodWinEventProc As LongLong, ByVal pfnWinEventProc As LongLong, _
                    ByVal idProcess As Long, ByVal idThread As Long, ByVal dwFlags As Long) As Long
                    
        Private Declare PtrSafe Function GetCurrentProcessId Lib "kernel32" () As Long
        Private Declare PtrSafe Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
        Private Declare PtrSafe Function UnhookWinEvent Lib "user32.dll" (ByVal hWinEventHook As Long) As Long
        
        Private handlColl As Collection
    
        Public Sub StartMonitoring() 'it can be called from a Workbook/Worksheet event
            StartFocusMonitoring
        End Sub
        
        Public Function StartFocusMonitoring() As Long
          If handlColl Is Nothing Then Set handlColl = New Collection
          StartFocusMonitoring = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, 0&, _
                                            AddressOf WinEventFunc, 0, 0, WINEVENT_OUTOFCONTEXT)
          handlColl.aDD StartFocusMonitoring
        End Function
        
        Public Sub StopEventHook(lHook As Long)
          Dim LRet As Long
          If lHook = 0 Then Exit Sub`
       
          LRet = UnhookWinEvent(lHook)
        End Sub
        
        Public Sub StopMonitoring() 'it must be called manualy or by an event when need to stop monitoring...
          'it did not work until I changed the StopEventHook declaration, using ByVal instead of ByRef
          Dim vHook As Variant, lHook As Long
          For Each vHook In handlColl
            lHook = vHook
            StopEventHook lHook
          Next vHook
        End Sub
        
        Public Function WinEventFunc(ByVal HookHandle As Long, ByVal LEvent As Long, _
                                ByVal hWnd As Long, ByVal idObject As Long, ByVal idChild As Long, _
                                ByVal idEventThread As Long, ByVal dwmsEventTime As Long) As Long
          'In case of an error the application will crush. So, bypassing the error is good to be done...`
          On Error Resume Next
          Dim thePID As Long`
        
          If LEvent = EVENT_SYSTEM_FOREGROUND Then
            GetWindowThreadProcessId hWnd, thePID
            If thePID = GetCurrentProcessId Then
              'Do not use here a MsgBox, because after pressing OK Excel application
              'will receive focus and you will stay in an infinite loop...
              Application.OnTime Now, "Event_GotFocus"
            Else
              Application.OnTime Now, "Event_LostFocus"
            End If
          End If
          On Error GoTo 0
        End Function
        
        Public Sub Event_GotFocus()
            Range("a1").value = "Received Focus"
            Range("a2").value = ""
        End Sub
        
        Public Sub Event_LostFocus()
           Range("a2").value = "Lost focus"
           Range("a1").value = ""
        End Sub