GetDoubleClickTime returns 0 unexpectedly

Viewed 619

We found a problem in our software with some customers after they upgraded their Windows 10 installation to version 2004 (May 2020 Update).

Server-side code in a webservice application creates a DevExpress PDF Viewer control and this failed with the error message "Interval cannot be 0". (I know creating a visual control inside a webservice is not a good idea, but this is legacy code and not trivial to change).

An analysis showed that the problem is that the control tries to create a .net WinForms Timer component and setting its Interval property to the result of SystemInformation.DoubleClickTime (which is just a wrapper for the GetDoubleClickTime winapi function). The error happens because the DoubleClickTime value is unexpectedly 0.

Why does this happen and is there some workaround?

3 Answers

The Windows API function “GetDoubleClickTime” is used to query the maximum number of milliseconds between two mouse clicks so that the two clicks are counted as one double click instead.

In Windows 10 Version 2004 this function unexpectedly returns 0 when executed in the context of a batch login, which means for example:

  • Code inside a Windows service
  • Code in applications that are started from a Windows service
  • Server-side code in web applications in IIS
  • Code in applications started from “planned tasks” in Windows with the setting “Run whether user is logged on or not”

In all these cases, there is no user interface. Executed code (in my case it is very old legacy code that doesn’t have a separation between user interface and business rules yet) could still query the value and then fail if 0 is returned unexpectedly. In my case, for example, a third party user interface control is instantiated which fails when trying to set a .net Windows Forms Timer based on the system double click time.

The same scenario returned values > 0 in Windows 10 before the update to Version 2004.

How to reproduce the bug

Using the following simple C# application

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);
        }
    }
}

Use the Microsoft Tool DebugView (with the setting “Capture Global Win32” enabled) to see the output from Trace.WriteLine.

Then create a Task in the Windows Task Scheduler to execute the compiled application. Use the setting “Run whether user is logged on or not”. You will see the output is

DoubleClickTime: 0

If you execute the compiled application directly, you will see the correct output

DoubleClickTime: 500

(Or some other value depending on your mouse settings).

In previous Windows 10 versions, a value higher than 0 was returned in both cases.

The same effect can be seen when code runs in a Windows service or in a web application in an IIS application pool. Probably also in other cases whenever code runs in the context of a batch logon.

How to solve the issue

  • Wait for Microsoft to fix the issue in a future update.
  • Advise customers to not install the Windows 10 2004 update or return to the previous Windows 10 version if necessary
  • Patch your code and make sure it can handle the case that GetDoubleClickTime returns 0. If necessary, contact vendors of third-party libraries to patch their libraries.

References

I have also published this as a blog post:

DevExpress is publishing a patch to their PDF Viewer component:

I am facing the same issue. I even tried to use WinAPI directly:

[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);

But surprisingly, the set SetDoubleClickTime has no effect(returns false) and the Marshal.GetLastWin32Error() returns ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION(1459)...

When I run from an interative session, everything works as expected. My issue lies on a legacy 3rd-part component, which we cannot modify the constructor... :-(

So far, a workaround was to run the build process(We get it on the build via the LC.exe) using “psexec -s -i” ... But maybe anyoene has another/better approach?

And I forgot to mention, this is hapenning on a

Windows 10 20H2 (Build 19042.985)

BR

Pedro

The main cause is that you are under different windows stations, the operation requires an interactive window station..

In the case of run directly, you will run on the interactive window station: "WinSta0";

And in the case of "Run whether user is logged on or not", you will be running in the background, and the station name is similar to "Service -0x*-*$".

I can reproduce this issue, and get an error code ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION(1459): This operation requires an interactive window station.(although the documentation does not mention that it can be obtained using GetLastError, the error code is for reference only)

As a workaround, the data is stored in the registry:

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

You could try to convert the string to the UINT.

Related