c# - GetLastInputInfo 不返回 dwTime

标签 c# winforms winapi interop user32

我有以下代码:

using System;
using System.Runtime.InteropServices;

public class WindowsFunctions
{
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

    public static int TicksSinceLastInput()
    {
        var info = new LASTINPUTINFO();
        GetLastInputInfo(ref info);
        var lastInputTickCount = info.dwTime;
        return (int)lastInputTickCount;
    }
}

[StructLayout(LayoutKind.Sequential)]
struct LASTINPUTINFO
{
    public static readonly int SizeOf = Marshal.SizeOf(typeof(LASTINPUTINFO));

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 cbSize;
    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dwTime;
}

但是,在运行时,info.dwTime 为零。

在VS2019 IDE中运行

更新:
我尝试使 TicksSinceLastInput 不是静态的,但无论如何都会失败。
我失败的单元测试现在是:

[TestMethod]
public void TestTicksSinceLastInput()
{
    var funcs = new WindowsFunctions();
    var ticks = funcs.TicksSinceLastInput();
    Assert.IsTrue( ticks > 0);
}

更新:
我的代码现在是:

public class WindowsFunctions
{
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

    public  int TicksSinceLastInput()
    {
        var info = new LASTINPUTINFO();
        var result = GetLastInputInfo(ref info);
        var lastInputTickCount = info.dwTime;
        return (int)lastInputTickCount;
    }
}

结果被设置为 false。

最佳答案

LASTINPUTINFO的声明看起来,来自 PInvoke.net .
该结构包含一个静态 int:

public static readonly int SizeOf = Marshal.SizeOf(typeof(LASTINPUTINFO));

它可能看起来像是定义结构体的大小,但实际上没有实际用途。

在您的原始代码中,结构的 cbSize成员未初始化,但必须:它指定结构本身的大小;分配它是强制性的。

GetLastInputInfo函数声明正确:

[DllImport("user32.dll")]
static extern bool GetLastInputInfo(ref LASTINPUTINFO info);

其返回类型为BOOL (定义为 typedef int BOOL ),而不是 BOOLEAN (定义为 typedef BYTE BOOLEAN )。
BOOL是托管的,它不需要:

[return: MarshalAs(UnmanagedType.Bool)]

LASTINPUTINFO的声明和初始化可以简化结构,以包含初始化其成员的非空构造函数:

[StructLayout(LayoutKind.Sequential)]
struct LASTINPUTINFO
{
    public uint cbSize;
    public uint dwTime;

    public LASTINPUTINFO(uint init) {
        cbSize = (uint)Marshal.SizeOf<LASTINPUTINFO>();
        dwTime = init;
    }
}

其成员的类型是:

  • UINT cbSize :UINT定义为typedef unsigned int UINT ,无符号整数。 它是托管类型,不需要(此处)[MarshalAs(UnmanagedType.U4)]
  • DWORD dwTime :DWORD定义为typedef unsigned long DWORD ,这是一个 32 位无符号整数。仍然受管理,它不需要(此处)[MarshalAs(UnmanagedType.U4)] .

当然,指定编码类型不会有什么坏处(当它正确时)。


示例用法,使用计时器显示自上次输入以来经过的毫秒数:

// Better resolution than System.Windows.Forms.Timer
System.Timers.Timer sysIdleTimer = null;
// [...]

protected override void OnLoad(EventArgs e) {
    base.OnLoad(e);

    sysIdleTimer = new System.Timers.Timer() {
        Interval = 100,
        SynchronizingObject = this // Marshal events to the UI Thread
    };
    sysIdleTimer.Elapsed += OnTimerElapsed;
    sysIdleTimer.Start();
}

static uint GetLastInputTimeMilliseconds()
{
    var info = new LASTINPUTINFO(0);
       
    if (GetLastInputInfo(ref info)) {
        // Valid within 24.9 days of machine activity
        uint idleTime = (uint)Environment.TickCount - info.dwTime;
        return idleTime;
    }
    return 0;
}

protected void OnTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    // Shows the Input Idle time in a Label
    lblInputIdle.Text = $"Idle Time: {GetLastInputTimeMilliseconds()} milliseconds";
}

GetLastInputInfo IdleTime

关于c# - GetLastInputInfo 不返回 dwTime,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67797365/

相关文章:

c# - 有没有更简单的方法可以将多个可观察集合组合成一个可观察集合?

c# - CS0029 读取用户输入时

c# - 用多线程写入excel文件

c++ - GetFinalPathNameByHandle() 结果没有前置 '\\?\'

c++ - 带有 CWinThread 指针数组的 WaitForMultipleObjects

c# - 如何从 HttpResponse 对象读取 html

c# - Winforms 应用程序中的可怕 "Callback chains"

c# - 如何垂直自动调整 winforms datagridview 控件的大小,使其行始终可见

c# - 将 MYSQL 连接到 Windows 窗体 C# 的最安全方法

c++ - 用 SOIL 保存位图时 BMP 损坏。截图区