none
GetRawInputDeviceList (pinvoked from User32.dll) does not work if called in .Net Service RRS feed

  • Question

  • I'm working on an C# application that uses a 3DConnexion Joystick to control some external hardware that is attached to the computer. I decieded to use the Raw Input functions that may be found in user32.dll.

    Meanwhile almost all things are running and I'm able to control my Hardware using the Joystick - if I start my program from the command line or from Visual Studio in a debug session. So far so good.

    But: My application normally runs as a Windows Service and in that context the function GetRawInputDeviceList does not work properly.

    See this code:

        public class Tools
        {
            [StructLayout(LayoutKind.Sequential)]
            internal struct RAWINPUTDEVICELIST
            {
                public IntPtr hDevice;
                [MarshalAs(UnmanagedType.U4)]
                public uint dwType;
            }
    
            [SecurityCritical, SuppressUnmanagedCodeSecurity]
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            extern static int GetRawInputDeviceList(IntPtr pRawInputDeviceList, ref uint uiNumDevices, uint cbSize);
    
            public static void EnumerateHIDDevices()
            {
                uint deviceCount = 0;
                uint dwSize = (uint)(Marshal.SizeOf(typeof(RAWINPUTDEVICELIST)));
    
                if (GetRawInputDeviceList(IntPtr.Zero, ref deviceCount, dwSize) == 0)
                {
                    System.Diagnostics.Trace.WriteLine(string.Format("LastError after calling {0}: 0x{1:X}", "GetRawInputDeviceList 1", Marshal.GetLastWin32Error()));
                    System.Diagnostics.Trace.WriteLine(string.Format("dwSize={0} deviceCount={1}", dwSize, (int)deviceCount));
    
                    IntPtr pRawInputDeviceList = Marshal.AllocHGlobal((int)(dwSize * (int)deviceCount));
                    GetRawInputDeviceList(pRawInputDeviceList, ref deviceCount, dwSize);
    
                    System.Diagnostics.Trace.WriteLine(string.Format("LastError after calling {0}: 0x{1:X}", "GetRawInputDeviceList 2", Marshal.GetLastWin32Error()));
                    System.Diagnostics.Trace.WriteLine(string.Format("Found {0} raw HID devices", (int)deviceCount));
                }
            }
        }

    After calling GetRawInputDeviceList the parameter deviceCount always returns 0 - also if the joystick is attached to the PC and also if the same code works if called in an executable from command line. It only fails if called from Service...

    I tried several things using marshalling and so on, but no success. It always runs if called as executable from command line but not in a Windows Service.

    Has anyone an idea what is happend here?

    (If it helps: I have a full working example application that illustrates the problems (working on command line, failing as Service)).

     

    Monday, June 2, 2014 1:26 PM

Answers

  • I doubt that you'll be able to use the Raw Input API from a service. Services run a different session and they don't have access to desktop resources, they're not supposed to read the keyboard, display windows etc.
    • Marked as answer by Felsenquelle Tuesday, June 3, 2014 8:35 AM
    Monday, June 2, 2014 1:56 PM
    Moderator

All replies

  • I doubt that you'll be able to use the Raw Input API from a service. Services run a different session and they don't have access to desktop resources, they're not supposed to read the keyboard, display windows etc.
    • Marked as answer by Felsenquelle Tuesday, June 3, 2014 8:35 AM
    Monday, June 2, 2014 1:56 PM
    Moderator
  • Thanks for your answer!

    Is this a guess or a fact?

    (Found no restrictions accessing resources until now. Seems that I have to think about the reasons...)

    Monday, June 2, 2014 2:42 PM
  • What I know for a fact is that (starting with Vista) services run in a different session and because of that they can't access the interactive desktop. And that means they cannot get keyboard input or display windows on the desktop

    What I guess is that the raw input is no different and it requires access to an interactive desktop just like normal input. I'm 99.9% sure that this guess is correct for keyboard and mouse input but I'm not sure if this applies to a joystick.

    Try checking "Allow service to interact with the desktop" on the "Log On" tab of the service properties. If it works then you found the problem though not necessary the solution because using this option is not recommended.

    There's a lot of information about this on the Internet, here's one blog post I found on a quick search: http://blogs.technet.com/b/voy/archive/2007/02/23/services-isolation-in-session-0-of-windows-vista-and-longhorn-server.aspx

    Monday, June 2, 2014 3:22 PM
    Moderator
  • Setting the flag "Allow service to interact with the desktop" did not change anything.

    I think we are basically talking about two different things: My problem is, that the win32 function GetRawInputDeviceList does only return 0 for the number of devices - there is no access to the joystick or to any other device at this point.

    So it would mean, that the access to any HID device is forbidden for a service...

    Tuesday, June 3, 2014 7:00 AM
  • "I think we are basically talking about two different things: My problem is, that the win32 function GetRawInputDeviceList does only return 0 for the number of devices"

    Which likely means that HID devices are attached to the interactive desktop so the service can't see any of them. Come to think of it, that's natural, the raw input API isn't that "raw". It's still routed through HWND and window message and that means that's session/desktop dependent. It's not like you're talking directly to the HID device.

    Tuesday, June 3, 2014 8:14 AM
    Moderator
  • Yes, that HWND stuff may explain it...

    So possibly using another mechanism like DirectInput or so should do the things.

    Thanks again!

    Tuesday, June 3, 2014 8:31 AM
  • "So possibly using another mechanism like DirectInput or so should do the things."

    Nope, DirectInput uses raw input under the covers.

    Tuesday, June 3, 2014 8:33 AM
    Moderator