代码之家  ›  专栏  ›  技术社区  ›  NineBerry

GetDoubleClickTime意外返回0

  •  0
  • NineBerry  · 技术社区  · 4 年前

    我们发现,一些客户在将Windows 10安装升级到2004版(2020年5月更新)后,我们的软件出现了问题。

    Web服务应用程序中的服务器端代码创建了DevExpress PDF Viewer控件,但此操作失败,并显示错误消息“Interval不能为0”。(我知道在Web服务中创建可视化控件不是一个好主意,但这是遗留代码,更改起来并不容易)。

    分析表明,问题在于控件试图创建.net WinForms Timer 组件及其设置 Interval 财产的结果 SystemInformation.DoubleClickTime (这只是包装 GetDoubleClickTime winapi函数)。发生错误的原因是 DoubleClickTime 值意外为0。

    为什么会发生这种情况,是否有一些解决方法?

    0 回复  |  直到 4 年前
        1
  •  5
  •   NineBerry    4 年前

    Windows API函数GetDoubleClickTime用于查询两次鼠标单击之间的最大毫秒数,以便将两次单击计算为一次双击。

    In Windows 10 2004版 在批处理登录的上下文中执行此函数时,意外返回0,例如:

    • Windows服务中的代码
    • 从Windows服务启动的应用程序中的代码
    • IIS中web应用程序的服务器端代码
    • 应用程序中的代码从Windows中的计划任务开始,使用 设置无论用户是否登录都运行

    在所有这些情况下,都没有用户界面。执行的代码(在我的例子中,它是非常旧的遗留代码,用户界面和业务规则之间还没有分离)仍然可以查询该值,如果意外返回0,则会失败。例如,在我的例子中,实例化了一个第三方用户界面控件,该控件在尝试根据系统双击时间设置.net Windows窗体计时器时失败。

    同一场景返回的值>在更新到2004版本之前,Windows 10中的0。

    如何重现bug

    使用以下简单的C#应用程序

    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    
    namespace WindowsFormsApp14
    {
     
        static class Program
        {
            [DllImport("user32.dll")]
            static extern uint GetDoubleClickTime();
             
            [STAThread]
            static void Main()
            {
                // Same result with var doubleClickTime = 
                // System.Windows.Forms.SystemInformation.DoubleClickTime;
                var doubleClickTime = GetDoubleClickTime();
     
                Trace.WriteLine("DoubleClickTime: " + doubleClickTime);
            }
        }
    }
    

    使用Microsoft工具 DebugView (启用Capture Global Win32设置)查看Trace的输出。WriteLine。

    然后在Windows任务计划程序中创建一个任务来执行编译的应用程序。使用设置“无论用户是否登录都运行”。您将看到输出为

    双击时间:0

    如果直接执行编译后的应用程序,您将看到正确的输出

    双击次数:500

    (或根据鼠标设置的其他值)。

    在以前的Windows 10版本中,在这两种情况下都返回了大于0的值。

    当代码在Windows服务或IIS应用程序池中的web应用程序中运行时,也可以看到相同的效果。可能在其他情况下,只要代码在批登录的上下文中运行。

    如何解决这个问题

    • 等待Microsoft在将来的更新中修复此问题。
    • 建议客户不要安装Windows 10 2004更新,如有必要,请返回到以前的Windows 10版本
    • 修补您的代码,并确保它可以处理GetDoubleClickTime返回0的情况。如有必要,请联系第三方库的供应商来修补他们的库。

    工具书类

    我也在博客上发表了这篇文章:

    DevExpress正在发布其PDF查看器组件的补丁:

        2
  •  2
  •   PCBL    3 年前

    我也面临着同样的问题。我甚至尝试直接使用WinAPI:

    [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
    public static extern int GetDoubleClickTime();
    
    [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
    public static extern bool SetDoubleClickTime(int newValue);
    

    但令人惊讶的是,集合SetDoubleClickTime没有效果(返回false),Marshal也没有效果。GetLastWin32Error()返回ERROR_REQUIRESINTERACTIVE_WINDOWSTATION(1459)。。。

    当我从互动会话中跑出来时,一切都按预期进行。我的问题在于遗留的第三部分组件,我们无法修改构造函数…:-(

    到目前为止,一种解决方法是使用psexec-s-i运行构建过程(我们通过LC.exe在构建过程中获取它)。。。但也许有人有另一种/更好的方法?

    我忘了说,这是在一个

    Windows 10 20H2 (Build 19042.985)
    

    BR

    佩德罗

        3
  •  1
  •   Drake Wu    4 年前

    主要原因是您在不同的窗口站下,操作需要一个交互式窗口站。。

    在直接运行的情况下,您将在交互式窗口站上运行: "WinSta0" ;

    在“无论用户是否登录都运行”的情况下,您将在后台运行,站点名称类似于 "Service -0x*-*$" .

    我可以重现此问题,并获得错误代码 ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION(1459) :此操作需要一个交互式窗口站。(尽管文件没有提到可以通过以下方式获得 GetLastError ,错误代码仅供参考)

    作为解决方法,数据存储在注册表中:

    HKEY_CURRENT_USER\Control Panel\Mouse\DoubleClickSpeed
    Type = REG_SZ
    Data = 500
    

    您可以尝试将字符串转换为 UINT .