Importing UserKey dll in .Net

Keith
I am attempting to get the 6 hardware buttons (K1-6) to send keys into a
compact framework app. I thought the way to do this would be to run
KEY_Init in the UserKey dll. The import (below) fails with an unknown
method error. What am I doing wrong, and is there a better way to get the
button events? Thanks Keith

[DllImport("userkey.dll")]
public static extern bool KEY_Init(int dwContext);

[DllImport("userkey.dll")]
public static extern bool KEY_Deinit(int hDeviceContext);

Keith
One step closer? I have run the KeyTest example app, and K1, K2 do not
work. The LEDs do, so I am guessing the UserKey driver has not started? It
is in the registry. Any ideas? Thanks,
Keith

Keith
And one more piece of info... The Button testing app,
(\Windows\Buttons.exe) does work. Is the source code for that anywhere? It
should be apparent by now that I'm completely confused.
Keith

Guy
Hello Keith,

userkey is a stream driver, so you use can use CreateFile and ReadFile to
access the button states.
I was under the impression that it generated key press events, but I've
been unable to get that to work...

Guy
I've quickly just knocked up this bit of c# code...


    public class ReadButtonsClass
    {
        [DllImport("coredll", SetLastError = true)]
        static extern IntPtr CreateFile(String lpFileName, UInt32
dwDesiredAccess, UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32
dwCreationDisposition, UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile);

        [DllImport("coredll.dll")]
        private static extern int ReadFile(
        IntPtr hFile,
        byte[] lpBuffer,
        int nNumberOfBytesToRead,
        ref int lpNumberOfBytesRead,
        ref int lpOverlapped);

        IntPtr KeyRdr;
        public enum Keys2440 { K1, K2, K3, K4, K5, K6 };

        Queue<Keys2440> KeyQueue = new Queue<Keys2440>();
        Keys2440[] KeyLookUp = {Keys2440.K1, Keys2440.K2, Keys2440.K3,
Keys2440.K4, Keys2440.K5, Keys2440.K6};

        public ReadButtonsClass()
        {
            Thread InputReaderThread = new Thread(new
ThreadStart(InputReader));
            KeyRdr = CreateFile("KEY1:", 0, 0, (IntPtr)0, 0, 0, (IntPtr)0);
            InputReaderThread.Start();

        }

        private void InputReader()
        {
            byte[] buf = new byte[10];

            while (true)
            {
                int bytesrd = 0;
                int ov = 0;

                ReadFile(KeyRdr, buf, 6, ref bytesrd, ref ov);
                for (int i = 0; i < bytesrd; i++)
                {
                    if (buf[i] != 0)
                    {
                        KeyQueue.Enqueue(KeyLookUp[i]);
                    }
                }
            }


        }

        public bool AnyEvents()
        {
            return KeyQueue.Count != 0;
        }

        public Keys2440 GetEvent()
        {
            return KeyQueue.Dequeue();
        }
    }

Keith
Guy,
Thank you so much for your help. When I try this, I get a good file handle
out of CreateFile, but Readfile always returns 0 bytesrd. Any ideas?
Thanks,
Keith

Guy
Hi Keith

Hmmm..What CE version are you using? (I'm using 5.0) ReadFile should block
until an event triggers and should return 6 bytes (as can be seen from the
driver code itself)

DWORD ret = WaitForSingleObject(APIEvent, INFINITE);
  if (ret != WAIT_OBJECT_0) {
    return FALSE;
  }
  RETAILMSG(1,(TEXT("USERKEY: Reset\r\n")));

  memcpy(pBuffer, KeyValues, 6);

  return 6;

What return value do you get back from ReadFile()?

Keith
Ah Ha! Thanks for the hint. I finally got it. I'm in CE6.0. the CreateFile
should be slightly different, and I cleaned up the ReadFile. this works:

    public class ReadButtonsClass
    {
        [DllImport("coredll", SetLastError = true)]
        static extern IntPtr CreateFile(String lpFileName, UInt32
dwDesiredAccess,
            UInt32 dwShareMode, IntPtr lpSecurityAttributes, 
            UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes,
IntPtr hTemplateFile);

        [DllImport("coredll.dll", SetLastError = true)]
        private static extern int ReadFile(IntPtr hFile, byte[] lpBuffer,
Int32 nNumberOfBytesToRead, ref Int32 lpNumberOfBytesRead, IntPtr
lpOverlapped);

        [DllImport("coredll.dll", SetLastError = true)]
        public static extern bool CloseHandle(IntPtr hObject);

        [DllImport("coredll.dll")]
        private static extern int GetLastError();


        IntPtr KeyRdr;
        public enum Keys2440 { K1, K2, K3, K4, K5, K6 };

        Queue<Keys2440> KeyQueue = new Queue<Keys2440>();
        Keys2440[] KeyLookUp = {Keys2440.K1, Keys2440.K2, Keys2440.K3,
Keys2440.K4, Keys2440.K5, Keys2440.K6};

        private bool m_Stop = false;

        public ReadButtonsClass()
        {
        }

        public void Start()
        {
            m_Stop = false;
            Thread InputReaderThread = new Thread(new
ThreadStart(InputReader));
            KeyRdr = CreateFile("KEY1:", (uint)FileAccess.Read, 0,
(IntPtr)0, 0, 0, (IntPtr)0);
            InputReaderThread.Start();
        }

        public void Stop()
        {
            m_Stop = true;
        }

        private void InputReader()
        {
            byte[] buf = new byte[10];
            int res;

            while (!m_Stop)
            {
                int bytesrd = 0;
                res = ReadFile(KeyRdr, buf, 6, ref bytesrd, IntPtr.Zero);
                if (res != 0)
                {
                    for (int i = 0; i < bytesrd; i++)
                    {
                        if (buf[i] != 0)
                        {
                            KeyQueue.Enqueue(KeyLookUp[i]);
                        }
                    }
                }
                else
                {
                    res = GetLastError();
                }
            }
            CloseHandle(KeyRdr);
        }

        public bool AnyEvents()
        {
            return KeyQueue.Count != 0;
        }

        public Keys2440 GetEvent()
        {
            return KeyQueue.Dequeue();
        }
    }

    public enum FileAccess : uint
    {
        /// <summary>
        /// Read access to the file.  Data can be read from the file.
        /// </summary>
        Read = 0x80000000,
        /// <summary>
        /// Write access to the file.  Data can be written to the file.
        /// </summary>
        Write = 0x40000000,
        /// <summary>
        /// Execute permission. The file can be executed.
        /// </summary>
        Execute = 0x20000000,
        /// <summary>
        /// All permissions.
        /// </summary>
        All = 0x10000000
    }

Thank you so much for your help,
Keith

Guy
Cool, glad you got it sorted. I totally forgot the read / write
permissions...sleep deprivation and old age I suppose!
I guess ideally the Enqueue and Dequeue need locks around them as they're
not thread safe.