【问题标题】:Eventhandler "bug" using VB.NET with windows forms使用带有 Windows 窗体的 VB.NET 的事件处理程序“错误”
【发布时间】:2013-07-27 01:51:20
【问题描述】:

我有以下代码:

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)

    Const WM_SYSCOMMAND As Integer = &H112
    Const SC_SCREENSAVE As Integer = &HF140

    MyBase.WndProc(m)
    If bloqueado = 0 Then
        If m.Msg = WM_SYSCOMMAND AndAlso m.WParam.ToInt32 = SC_SCREENSAVE Then
            Timer2.Start()
            inicio = Now
            pausa = pausa + 1
            AddHandler Application.Idle, AddressOf Application_Idle
        End If
    End If
End Sub

Private Sub Application_Idle(ByVal sender As Object, ByVal e As EventArgs)
    Dim newitem As ListViewItem
    Dim diferença As TimeSpan

    'MsgBox(Now.ToString)'
    Debug.Print(Now.ToString)
    fim = Now
    diferença = fim - inicio
    Timer2.Stop()
    newitem = New ListViewItem
    newitem.Text = pausa
    newitem.SubItems.Add(inicio.ToLongTimeString)
    newitem.SubItems.Add(fim.ToLongTimeString)
    newitem.SubItems.Add(diferença.ToString.Substring(0, 8))
    ListView1.Items.Add(newitem)
    parcial = parcial & pausa & vbTab & vbTab & inicio.ToLongTimeString & vbTab & vbTab & fim.ToLongTimeString _
         & vbTab & vbTab & diferença.ToString.Substring(0, 8) & vbTab & vbTab & "   screensaver" & System.Environment.NewLine
    RemoveHandler Application.Idle, AddressOf Application_Idle
End Sub

基本上第一部分检测屏幕保护程序何时激活并创建 application.idle 事件处理程序,第二部分检测活动时运行一堆代码并删除处理程序。

除了一点,一切都很好:

如您所见,当屏幕保护程序变为活动状态时,我有 inicio = now,当检测到活动时(当屏幕保护程序变为非活动状态时),我有 inicio = now,所以我应该有 2 个不同的时间,但如果我有它,就像我发布了 2 个日期时间将是相同的。如果您注意到我有一个 msgbox 在评论中显示现在(当屏幕保护程序停止时),如果我将其从评论中删除,则 2 个日期时间将不同且正确(我使用计时器来确保结果)

现在我的问题: 为什么它需要更新 now 的消息框,为什么它在 debug.print 中不起作用?

有没有办法解决这个问题/更新now var,而不必使用消息框(我不希望应用有弹出消息)

如果我真的必须为此目的使用 msgbox,有没有办法让它不发送弹出窗口或立即自动单击确定,以便它立即消失?

编辑:

我一直在搜索,我找到了这段代码:

Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    Public Function IsSNRunning() As Boolean
        IsSNRunning = (FindWindow("WindowsScreenSaverClass", vbNullString) <> 0)
    End Function

    Private Sub Timer3_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer3.Tick
        If IsSNRunning() Then
            'Screen Saver Is Running
        Else
            Timer3.Stop()
            code
        End If
End Sub

我在捕获屏幕保护程序开始的部分中使用Timer3.Start(),我的想法是如果我在知道屏幕保护程序是否打开时启动计时器,那么当我将 IsSNRunning 设为 false 时是屏幕保护程序停止运行时,但它不起作用,任何想法为什么?

【问题讨论】:

  • fim = 现在检测到活动时 Application.Idle 如何提醒您活动? 为什么它现在需要更新消息框,为什么它在 debug.print 中不起作用? 大概消息框会立即运行(Application.Idle 是一个非常常见的事情)但会阻止代码从继续,直到您移动鼠标、清除屏幕保护程序并看到消息框。当您关闭消息框时,Debug.Print 代码会以当前时间运行。
  • application_idle 是一个与activity相关的事件
  • 这与应用程序即将变为“空闲”有关,因此没有活动...让您的事件处理程序发出哔声而不是显示消息框。
  • 嗯。那么我如何检测活动?像鼠标移动或计时或按键?以便我知道屏幕保护程序何时结束?
  • 您认为pausa = pausa + 1AddHandler Application.Idle, AddressOf Application_Idle 执行需要多长时间?我怀疑它比你在两次调用Now 时捕获的要快得多,尤其是因为第一次是一个简单的增量。

标签: vb.net winforms visual-studio visual-studio-2012


【解决方案1】:

对 Application.Idle 做任何事情都是徒劳的。您的应用程序不仅在屏幕保护程序激活后立即进入空闲状态,而且在它运行时您也永远不会停止空闲状态。屏幕保护程序将活动桌面切换到专用的安全桌面,任何正在运行的程序都不会获得任何输入,直到它停用。

可以观察到桌面切换,SystemEvents.SessionSwitch 事件触发。

请注意,这样的代码相当缺乏实用性。好奇心是可以的,但总有很多东西要学。屏幕保护程序应位于列表的底部。

【讨论】:

    【解决方案2】:

    首先我要感谢你们的帮助,就像你说的 application.idle 不起作用,在你们的帮助下,我在 VB 中得到了这个解决方案:

    Imports System
    Imports Microsoft.Win32
    Imports System.Windows.Forms
    Imports System.Runtime.InteropServices
    
    <DllImport("user32.dll", CharSet:=CharSet.Auto)> Public Shared Function SystemParametersInfo(uAction As UInteger, _
        uParam As UInteger, ByRef lpvParam As Boolean, fWinIni As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function
    ' Check if the screensaver is busy running.'
    Public Shared Function IsScreensaverRunning() As Boolean
        Const SPI_GETSCREENSAVERRUNNING As Integer = 114
        Dim isRunning As Boolean = False
    
        If Not SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, isRunning, 0) Then
            ' Could not detect screen saver status...'
            Return False
        End If
    
        If isRunning Then
            ' Screen saver is ON.'
            Return True
        End If
    
        ' Screen saver is OFF.'
        Return False
    End Function
    
    
    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    
        Const WM_SYSCOMMAND As Integer = &H112
        Const SC_SCREENSAVE As Integer = &HF140
    
        MyBase.WndProc(m)
        If bloqueado = 0 Then
            If m.Msg = WM_SYSCOMMAND AndAlso m.WParam.ToInt32 = SC_SCREENSAVE Then
                Timer2.Start()
                Timer3.Enabled = True
                Timer3.Start()
                'here we that that the screensaver started running so we start a timer'
            End If
        End If
    End Sub
    
    Private Sub Timer3_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer3.Tick
    
        If IsScreensaverRunning() Then
            'Screen Saver Is Running'
        Else
            Timer3.Stop()
            Timer3.Enabled = False
            'Screen Saver Is not Running'
        End If
    
    End Sub
    

    因为计时器仅在屏幕保护程序运行时才开始运行,所以我们知道当您获得 timer3.stop 时就是屏幕保护程序停止运行的时间

    重要的是,不要在计时器停止之前放一个 msgbox,因为它不起作用,弹出窗口会显示并且它不会停止,所以会出现无数的弹出窗口(是的......我犯了那个错误: S)

    再次感谢您对我的帮助,希望它对将来的某人有所帮助

    【讨论】:

      猜你喜欢
      • 2011-09-23
      • 2016-12-16
      • 2011-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多