3

I have to develop a C# application which needs to make use of advanced gestures to improve the user experience. In order to do so, I need to get information when a certain gesture is invoked by the user.

Because WndProc is a taboo in .NET CE, I'm using OpenNETCE's Application2 and IMessageFilter classes to receive WM-traffic.

In my MessageFilter I look for WM_GESTURE messages and that's where I'm stuck.

I just don't get any meaningful result by calling this function:

https://msdn.microsoft.com/en-us/library/ee503217.aspx

BOOL GetGestureInfo(
        HGESTUREINFO hGestureInfo
        PGESTUREINFO pGestureInfo
);

Here's the relevant code:

public class TestMessageFilter : IMessageFilter
{
    [DllImport("coredll", SetLastError = true)]
    public static extern bool GetGestureInfo(IntPtr hGesture, ref GESTUREINFO lGesture);

    public static uint WM_GESTURE = 0x0119;

    public bool PreFilterMessage(ref Microsoft.WindowsCE.Forms.Message m)
    {
        // ...
        if (m.Msg == WM_GESTURE)
        {
            GESTUREINFO gi = new GESTUREINFO() {
                cbSize = (uint)Marshal.SizeOf(typeof(GESTUREINFO))
            };

            bool success = GetGestureInfo(m.LParam, ref gi);
            if (success)
            {
                // ...
            }
            else
            {
                int x = Marshal.GetLastWin32Error(); // => 87
            }
        }

        // ...
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct POINTS
    {
        public short x;
        public short y;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct GESTUREINFO
    {
        public UInt32 cbSize;
        public UInt32 dwFlags;
        public UInt32 dwID;
        public IntPtr hwndTarget;
        public POINTS ptsLocation;
        public UInt32 dwInstanceID;
        public UInt32 dwSequenceID;
        public UInt64 ullArguments;
        public UInt32 cbExtraArguments;
    }
}

It always gives me error code 87.

ERROR_INVALID_PARAMETER

Why does it not work? What's invalid? It's driving me nuts...

Many, many thanks in advance.

Edit: I found this post on the msdn forums which uses an IntPtr instead of a reference to the GestureInfo as the second parameter.

[DllImport("coredll.dll")]
static extern int GetGestureInfo(IntPtr hGestureInfo, [In, Out] IntPtr pGestureInfo);
// ...
GESTUREINFO gi = new GESTUREINFO();
gi.cbSize = 48;

IntPtr outGI = Marshal.AllocHGlobal(48);
Marshal.StructureToPtr(gi, outGI, false);

bool bResult = (GetGestureInfo(lParam, outGI) == 1);
bool bHandled = false;
Marshal.FreeHGlobal(outGI);
Marshal.PtrToStructure(outGI, gi);
// ...

But it procudes the same ERROR_INVALID_PARAMETER error for me.

Does nobody have a solution or another approach to obtain a GestureInfo from C#?

1 Answers1

2

I only have experience with Windows Embedded Compact 7 but it should not differ too much from 2013 - did you enable gestures first? (you probably did since you're receiving WM_GESTURE, but here's the code anyway):

[DllImport(User32Library)]
public static extern bool EnableGestures(IntPtr hWnd, GestureMask flags, uint scope);

[Flags]
public enum GestureMask : ulong
{
    TGF_GID_PAN = 0x10,
    TGF_GID_SCROLL = 0x100,
    TGF_GID_HOLD = 0x200,
    TGF_GID_SELECT = 0x400,
    TGF_GID_DOUBLESELECT = 0x800,
    TGF_GID_DIRECTMANIPULATION = 0x1000,
    TGF_GID_ALL = TGF_GID_PAN | TGF_GID_SCROLL | TGF_GID_HOLD | TGF_GID_SELECT | TGF_GID_DOUBLESELECT,// | TGF_GID_DIRECTMANIPULATION,
}

I chose to copy paste our working example; can't remember whether TGF_GID_DIRECTMANIPULATION was excluded from TGF_GID_ALL just for our convenience or because we had issues with it, sorry

bool enabled = EnableGestures(Handle, Native.GestureMask.TGF_GID_ALL, 0);

The following signature for GetGestureInfo works for our devices:

[DllImport("coredll.dll")]
public static extern bool GetGestureInfo(IntPtr hGestureInfo, ref GestureInfo pGestureInfo);

With the structs GestureInfo:

[StructLayout(LayoutKind.Sequential)]
public struct GestureInfo
{
    /// <summary>
    /// Specifies the size of the structure in bytes.  This must be set to Marshal.SizeOf(typeof(GESTUREINFO))
    /// </summary>
    public uint Size;
    /// <summary>
    /// Gesture Flags
    /// </summary>
    public GestureState State;
    /// <summary>
    /// Gesture Id
    /// </summary>
    public GestureKind Kind;
    /// <summary>
    /// HWND of the target winndow
    /// </summary>
    public IntPtr TargetWindow;
    /// <summary>
    /// Coordinates of start of gesture
    /// </summary>
    public short LocationX;
    /// <summary>
    /// Coordinates of start of gesture
    /// </summary>
    public short LocationY;
    /// <summary>
    /// Gesture Instance Id
    /// </summary>
    public uint InstanceId;
    /// <summary>
    /// Gesture Sequence Id
    /// </summary>
    public uint SequenceId;
    /// <summary>
    /// Arguments specific to gesture
    /// </summary>
    public ulong Arguments;
    /// <summary>
    /// Size of extra arguments in bytes
    /// </summary>
    public uint ExtraArguments;
}

GestureState:

[Flags]
public enum GestureState : uint
{
    /// <summary>
    /// The gesture has no associated state
    /// </summary>
    None = 0,
    /// <summary>
    /// The gesture is the beginning of pan gesture
    /// </summary>
    Begin = 1,
    /// <summary>
    /// The gesture is the end of a pan gesture that will transition into a scroll gesture
    /// </summary>
    Inertia = 2,
    /// <summary>
    /// The gesture is the end of a pan gesture
    /// </summary>
    End = 4
}

and GestureKind:

/// <summary>
/// The kind of gesture.
/// </summary>
public enum GestureKind : uint
{
    /// <summary>
    /// The beginning of a gesture operation.
    /// </summary>
    Begin = 1,
    /// <summary>
    /// The end of a gesture operation.
    /// </summary>
    End = 2,
    /// <summary>
    /// A pan gesture.
    /// </summary>
    Pan = 4,
    /// <summary>
    /// A scroll gesture.
    /// </summary>
    Scroll = 8,
    /// <summary>
    /// A hold gesture.
    /// </summary>
    Hold = 9,
    /// <summary>
    /// A select gesture.
    /// </summary>
    Select = 10,
    /// <summary>
    /// A double-select gesture.
    /// </summary>
    DoubleSelect = 11,
    /// <summary>
    /// Direct manipulation.
    /// </summary>
    DirectManipulation = 12,
}

The code to invoke the method:

GestureInfo gesture = new GestureInfo();
gesture.Size = (uint)Marshal.SizeOf(typeof(GestureInfo));
bool result = GetGestureInfo(lParam, ref gesture);

I don't see much difference between this and your first attempt; and the only thing that stands out in the MSDN example is the hardcoded size of 48 (probably meant to read any ExtraArguments).

We did choose to set a custom window procedure - but I don't see why that difference would matter.

C.Evenhuis
  • 25,996
  • 2
  • 58
  • 72