简体   繁体   中英

Windows CE (Win32) WndProc and capturing mouse events

I'm trying to implement multitouch gestures for graphing on Windows CE 6. I've tried two different methods... using the built-in gesture events and overriding WndProc to give me mouse downs and mouse move events.

With the built-in gesture events, I can't find a way to get the coordinates of both points of a multitouch gesture.

With overriding WndProc or using MouseDown/MouseMove events, it hides mouse down messages when you hold one finger on the screen, stopping multi-touch gestures.

Any advice?

I'm sorry, it's CE 7, not 6! Still not sure how to handle multi-touch though...

Acording to this http://msdn.microsoft.com/en-us/library/jj838851.aspx only Compact 2013 supports multitouch gestures. The OEM has to implement the driver to support multi-touch.

You may test your device using the internet browser on the device or call the TouchPanelGetDeviceCaps API to get information about multi-touch support ( http://msdn.microsoft.com/en-us/library/gg159143.aspx ).

If device is Windows CE 6 and not Compact 2013, I fear there is now way to get mutli-touch information in any app.

A few years ago I have used this API, today the gesture is not working in some devices. I'm looking for answers. My code looks like this, was working. You need to capture WM_GESTURE message to do something like zoom or pan.

using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace SmartDeviceCommon
{
    /// <summary>
    /// Gesture info structure
    /// </summary>
    [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;
    }

    [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
    }

    public enum GestureFlags : uint
    {
        Begin = 0x0001,
        Inertia = 0x0002,
        End = 0x0004,
        Symmetric = 0x0010
    }

    /// <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,
    }
    
    /// <summary>
    /// See Gestures.pdf
    /// </summary>
    public class Gestures
    {
        /// <summary>
        /// Enable gesture
        /// </summary>
        /// <param name="hwnd">handle of windows (IntPtr)</param>
        /// <param name="flags">TGestureMask</param>
        /// <param name="scope">TagGestureFlags => (ulong)TagGestureFlags</param>
        /// <returns></returns>
        [DllImport("coredll.dll", SetLastError = true)]
        public static extern bool EnableGestures(IntPtr hwnd, GestureMask flags, uint scope);
        /// <summary>
        /// Disable gesture
        /// </summary>
        /// <param name="hwnd">handle of windows (IntPtr)</param>
        /// <param name="flags">TGestureMask</param>
        /// <param name="scope">TagGestureFlags => (ulong)TagGestureFlags</param>
        /// <returns></returns>
        [DllImport("coredll.dll", SetLastError = true)]
        public static extern bool DisableGestures(IntPtr hwnd, GestureMask flags, uint scope);
        [DllImport("coredll.dll")]
        public static extern bool GetGestureInfo(IntPtr hGestureInfo, ref GestureInfo pGestureInfo);
    }

    [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,
    }
    
    public enum TagGestureFlags : ulong
    {
        BEGIN = 0x0000000000000002,
        END = 0x0000000000000008,
        PAN = 0x0000000000000100,
        ROTATE = 0x0000000000000200,
        SCROLL = 0x0000000000001000,
        HOLD = 0x0000000000002000,
        SELECT = 0x0000000000004000,
        DOUBLESELECT = 0x0000000000008000,
        LAST = 0x0000000000008000,
        MAX = 0x8000000000000000,
        SCOPE_WINDOW = 0,
        SCOPE_PROCESS = 1
    }



}

//typedef struct tagGESTUREINFO
//{
//    UINT cbSize;                /* Initialised to structure size */
//    DWORD dwFlags;              /* Gesture Flags */
//    DWORD dwID;                 /* Gesture ID */
//    HWND hwndTarget;            /* HWND of target window */
//    POINTS ptsLocation;         /* Coordinates of start of gesture */
//    DWORD dwInstanceID;         /* Gesture Instance ID */
//    DWORD dwSequenceID;         /* Gesture Sequence ID */
//    ULONGLONG ullArguments;     /* Arguments specific to gesture */
//    UINT cbExtraArguments;      /* Size of extra arguments in bytes */
//} GESTUREINFO, * PGESTUREINFO;


// winuser.h (C:\Program Files (x86)\Windows CE Tools\SDKs\BT-W SDK-HT\Include\Armv4i\winuser.h)
//**LINE 310**// Touch gesture command
//#define WM_GESTURE                      0x0119

///*
// * Gesture flags - GESTUREINFO.dwFlags
// */
//#define GF_BEGIN                        0x00000001
//#define GF_INERTIA                      0x00000002
//#define GF_END                          0x00000004
//#define GF_SYMMETRIC                    0x00000010

///*
// * Gesture IDs
// */
//#define GID_BEGIN                       1
//#define GID_END                         2
//#define GID_PAN                         4
//#define GID_ROTATE                      5
//#define GID_SCROLL                      8
//#define GID_HOLD                        9
//#define GID_SELECT                      10
//#define GID_DOUBLESELECT                11
//#define GID_DIRECTMANIPULATION          12
//#define GID_LAST                        12

Sample usage:

public partial class PreviewForm : Form
{
    public PreviewForm()
    {
        InitializeComponent();
    }

    private void PreviewForm_Load(object sender, EventArgs e)
    {
        if (SmartDeviceApplication.DesignTime) return;
        WndProcHooker.HookWndProc(this, hooker_OnGestureCallback, (uint)WM.GESTURE);
        bool enabled = Gestures.EnableGestures(Handle, GestureMask.TGF_GID_ALL, (uint)TagGestureFlags.SCOPE_WINDOW);
        if (!enabled)
        {
            MessageBox.Show("Gestures not enabled");
        }
        //hooker = new WndProcHooker(this, (uint)WM.GESTURE);
        //hooker.OnCallback += new WndProcHooker.WndProcCallback(hooker_OnGestureCallback);
        //hooker.Start();
        zoom = 1.0F;
    }

    public float Zoom
    {
        get { return zoom; }
        set
        {
            if (value > 3.0F)
            {
                value = 3.0F;
                delta = 0.25f;
            }
            else if (value < 1.0F)
            {
                previewPictureBox.Location = previewPicLocation;
                value = 1.0F;
                delta = 1.0f;
            }
            var _width = previewPictureBox.Width;
            var _height = previewPictureBox.Height;
            previewPictureBox.Width = (int)(previewPicSize.Width * value);
            previewPictureBox.Height = (previewPictureBox.Width * previewPicSize.Height) / previewPicSize.Width;
            previewPictureBox.Refresh();
            zoom = value;
        }
    }

    GestureInfo lastInfo;
    Point StartPos;
    Point OffSet;
    bool inMove;
    float zoom;
    float delta = 0.1f;
    //float deltaDirection = 1.0F;
    // 0,41 - 239,160

    int hooker_OnGestureCallback(IntPtr hwnd, uint msg, uint wParam, int lParam, ref bool handled)
    {
        GestureInfo gesture = new GestureInfo();
        gesture.Size = (uint)Marshal.SizeOf(typeof(GestureInfo));
        bool result = Gestures.GetGestureInfo((IntPtr)lParam, ref gesture);
        if (!result) return 0;
        switch (gesture.Kind)
        {
            case GestureKind.Begin:
                StartPos = new Point(gesture.LocationX, gesture.LocationY);
                OffSet = StartPos;
                inMove = false;
                break;
            case GestureKind.End:
                inMove = false;
                StartPos = new Point(0, 0);
                break;
            case GestureKind.Pan:
                var prevDelta = Math.Abs(((lastInfo.LocationY - StartPos.Y) + (lastInfo.LocationX - StartPos.X)));
                var curDelta = Math.Abs(((gesture.LocationY - StartPos.Y) + (gesture.LocationX - StartPos.X)));
                if (!inMove)
                {
                    if (curDelta > prevDelta)
                    {
                        Zoom += delta;
                    }
                    else
                    {
                        Zoom -= delta;
                    }
                    Debug.WriteLine(string.Format("StartPos X:{0} Y:{1}", StartPos.X, StartPos.Y));
                    Debug.WriteLine(string.Format("GesturePos X:{0} Y:{1}", gesture.LocationX, gesture.LocationY));
                    Debug.WriteLine(string.Format("Zoom {0} Delta {1} curDelta {2} prevDelta {3}",
                        Zoom, delta, curDelta, prevDelta));
                    //previewPictureBox.Location = new Point(previewPictureBox.Location.X - OffSet.X, previewPictureBox.Location.Y - OffSet.Y);
                    //previewPictureBox.Size = new Size(previewPictureBox.Size.Width + OffSet.X, previewPictureBox.Size.Height + OffSet.Y);
                }
                else
                {
                    OffSet.X = gesture.LocationX - lastInfo.LocationX;
                    if (OffSet.X > 0) OffSet.X = 5; else OffSet.X = -5;
                    OffSet.Y =  gesture.LocationY - lastInfo.LocationY;
                    if (OffSet.Y > 0) OffSet.Y = 5; else OffSet.Y = -5;
                    previewPictureBox.Location = new Point(previewPictureBox.Location.X + (OffSet.X * (int)Zoom), previewPictureBox.Location.Y + (OffSet.Y * (int)Zoom));
                    Debug.WriteLine(string.Format("pic Location X:{0} Y:{1}", previewPictureBox.Location.X, previewPictureBox.Location.Y));
                }
                previewPictureBox.Refresh();
                break;
            case GestureKind.Scroll:
                break;
            case GestureKind.Hold:
                inMove = true;
                Vibration.Play(1, 50, 0);
                break;
            case GestureKind.Select:
                break;
            case GestureKind.DoubleSelect:
                previewPictureBox.Location = previewPicLocation;
                previewPictureBox.Size = previewPicSize;
                picPanel.AutoScroll = false;
                picPanel.Location = backPanel.Location;
                picPanel.Size = backPanel.Size;
                Vibration.Play(2, 30, 20);
                previewPictureBox.Refresh();
                break;
            case GestureKind.DirectManipulation:
                break;
            default:
                break;
        }
        lastInfo = gesture;

        var pt1 = this.previewPictureBox.PointToScreen(previewPictureBox.Location);
        var gpt = new Point(gesture.LocationX, gesture.LocationY);
        var rect = new Rectangle(pt1.X, pt1.Y, previewPictureBox.Size.Width, previewPictureBox.Size.Height);
        //
        //System.Diagnostics.Debug.WriteLine(string.Format("Gesture Kind {0} State {1} Gesture{2} gpt{3},{4}", 
        //    gesture.Kind, gesture.State, gesture.Size, gpt.X, gpt.Y));
        //
        //System.Diagnostics.Debug.WriteLine(string.Format("Gestures Result {0} Position X:{1} Y:{2}",
        //    result, gesture.LocationX, gesture.LocationY));
        if (rect.Contains(pt1))
        {
            //System.Diagnostics.Debug.WriteLine("Handled");
            handled = true;
            return 1;
        }
        return 0;
    }
    
    private void PreviewForm_Closed(object sender, EventArgs e)
    {
         Gestures.DisableGestures(Handle, (ulong)TagGestureFlags.SCOPE_WINDOW, (uint)TagGestureFlags.SCOPE_WINDOW);
         WndProcHooker.UnhookWndProc(this, true);
    }
    
}


using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace SmartDeviceCommon
{
    public class WndProcHooker : IDisposable
    {
        #region IDisposable Members

        private Control ctrl;
        private uint msg;
        public event WndProcCallback OnCallback;
        private bool started;

        public WndProcHooker(Control ctrl, WM msg)
        {
            this.ctrl = ctrl;
            this.msg = (uint)msg;
            started = false;
        }

        public WndProcHooker(Control ctrl, uint msg)
        {
            this.ctrl = ctrl;
            this.msg = msg;
            started = false;
        }

        public int ControlCallBack(uint wParam, int lParam)
        {
            return WndProcHooker.OldCallback(ctrl.Handle, msg, wParam, lParam);
        }

        public void Start()
        {
            if (OnCallback == null) throw new InvalidOperationException("Callback is not set");
            if (ctrl == null) throw new InvalidOperationException("Hooker was disposed");
            WndProcHooker.HookWndProc(ctrl, OnCallback, msg);
        }

        public void Stop()
        {
            if (started)
            {
                started = false;
                WndProcHooker.UnhookWndProc(ctrl, false);
            }
        }

        public void Dispose()
        {
            if (ctrl != null && OnCallback != null && started)
            {
                WndProcHooker.UnhookWndProc(ctrl, true);
                ctrl = null;
                started = false;
            }
        }

        #endregion
        public delegate int WndProcCallback(IntPtr hwnd, uint msg, uint wParam, int lParam, ref bool handled);
        private static Dictionary<IntPtr, HookedProcInformation> hwndDict =
            new Dictionary<IntPtr, HookedProcInformation>();
        private static Dictionary<Control, HookedProcInformation> ctlDict =
            new Dictionary<Control, HookedProcInformation>();

        public static WndProcHooker.WndProcCallback HookWndProc(Control ctl, WndProcCallback callback, uint msg)
        {
            return HookWndProc(ctl, callback, msg, false, true);
        }

        public static WndProcHooker.WndProcCallback HookWndProc(Control ctl, WndProcCallback callback, uint msg, bool replic)
        {
            return HookWndProc(ctl, callback, msg, replic, true);
        }

        public static WndProcHooker.WndProcCallback HookWndProc(Control ctl, WndProcCallback callback, uint msg, bool replic, bool uniqueMsg)
        {
            WndProcCallback retValue = null;
            HookedProcInformation hpi = null;
            if (ctlDict.ContainsKey(ctl))
            {
                hpi = ctlDict[ctl];
            }
            else if (hwndDict.ContainsKey(ctl.Handle))
            {
                hpi = hwndDict[ctl.Handle];
            }
            if (hpi == null)
            {
                // If new control, create a new 
                // HookedProcInformation for it.
                hpi = new HookedProcInformation(ctl, new Win32.WndProc(WndProcHooker.WindowProc), replic);
                ctl.HandleCreated += new EventHandler(ctl_HandleCreated);
                ctl.HandleDestroyed += new EventHandler(ctl_HandleDestroyed);
                ctl.Disposed += new EventHandler(ctl_Disposed);

                // If the handle has already been created set the hook. If it 
                // hasn't been created yet, the hook will get set in the 
                // ctl_HandleCreated event handler. 
                if (ctl.Handle != IntPtr.Zero)
                {
                    hpi.SetHook();
                }
            }
            // Stick hpi into the correct dictionary. 
            if (ctl.Handle == IntPtr.Zero)
            {
                ctlDict[ctl] = hpi;
            }
            else
            {
                hwndDict[ctl.Handle] = hpi;
                if (hpi.messageMap.ContainsKey(msg))
                {
                    if (uniqueMsg) throw new ArgumentException("Hook already exists for this control");
                    retValue = hpi.messageMap[msg];
                }
            }
            // Add the message/callback into the message map.
            hpi.messageMap[msg] = callback;
            return retValue;
        }

        static void ctl_Disposed(object sender, EventArgs e)
        {
            Control ctl = sender as Control;
            if (ctlDict.ContainsKey(ctl))
            {
                UnhookWndProc(ctl, true);
                //ctlDict.Remove(ctl);
            }
            // not necessary to show error, if not hooked
            //else
            //    System.Diagnostics.Debug.Assert(false);
        }

        static void ctl_HandleDestroyed(object sender, EventArgs e)
        {
            // When the handle for a control is destroyed, we want to 
            // unhook its wndproc and update our lists
            Control ctl = sender as Control;
            if (hwndDict.ContainsKey(ctl.Handle))
            {
                HookedProcInformation hpi = hwndDict[ctl.Handle];
                UnhookWndProc(ctl, false);
            }
            //else
            //    System.Diagnostics.Debug.Assert(false);
        }

        static void ctl_HandleCreated(object sender, EventArgs e)
        {
            Control ctl = sender as Control;
            if (ctlDict.ContainsKey(ctl))
            {
                HookedProcInformation hpi = ctlDict[ctl];
                hwndDict[ctl.Handle] = hpi;
                ctlDict.Remove(ctl);
                hpi.SetHook();
            }
            else
                System.Diagnostics.Debug.Assert(false);
        }

        private static int WindowProc(IntPtr hwnd, uint msg, uint wParam, int lParam)
        {
            if (hwndDict.ContainsKey(hwnd))
            {
                HookedProcInformation hpi = hwndDict[hwnd];
                if (hpi.messageMap.ContainsKey(msg))
                {
                    WndProcCallback callback = hpi.messageMap[msg];
                    bool handled = false;
                    int retval = callback(hwnd, msg, wParam, lParam, ref handled);
                    if (hpi.Replicate)
                    {
                        var hpi2 = from c in hwndDict
                                   where c.Key != hwnd && c.Value.messageMap.ContainsKey(msg) && c.Value.Replicate
                                   select new { Handle = c.Key, MessageMap = c.Value.messageMap };
                        var item = hpi2.FirstOrDefault();
                        if (item != null)
                        {
                            var callback2 = item.MessageMap[msg];
                            var handled2 = true;
                            callback2(item.Handle, msg, wParam, lParam, ref handled2);
                        }
                        Debug.WriteLine("Replicate the message");
                    }
                    // if Handled
                    if (handled)
                    {
                        return retval;
                    }
                }

                // If the callback didn't set the handled property to true, 
                // call the original window procedure.
                var retValue = hpi.CallOldWindowProc(hwnd, msg, wParam, lParam);
                return retValue;
            }
            //TODO : Check this Assert
            //System.Diagnostics.Debug.Assert(false, "WindowProc called for hwnd we don't know about");
            System.Diagnostics.Debug.WriteLine("WindowProc called for hwnd we don't know about");
            return Win32.DefWindowProc(hwnd, msg, wParam, lParam);
        }

        public static int OldCallback(IntPtr hwnd, uint msg, uint wParam, int lParam)
        {
            if (!hwndDict.ContainsKey(hwnd)) return -1;
            HookedProcInformation hpi = hwndDict[hwnd];
            if (!hpi.messageMap.ContainsKey(msg)) return -1;
            // call the original window procedure.
            var retValue = hpi.CallOldWindowProc(hwnd, msg, wParam, lParam);
            return retValue;
        }

        public static void UnhookWndProc(Control ctl, uint msg)
        {
            if (ctl.IsDisposed) return;
            HookedProcInformation hpi = null;
            try
            {
                if (ctlDict.ContainsKey(ctl))
                    hpi = ctlDict[ctl];
                else if (hwndDict.ContainsKey(ctl.Handle))
                    hpi = hwndDict[ctl.Handle];
            }
            catch (ObjectDisposedException)
            {
                return;
            }
            // if we couldn't find a HookedProcInformation, throw 
            if (hpi == null) throw new ArgumentException("No hook exists for this control");

            // look for the message we are removing in the messageMap 
            if (hpi.messageMap.ContainsKey(msg))
                hpi.messageMap.Remove(msg);
            else
                // if we couldn't find the message, throw 
                throw new ArgumentException(string.Format("No hook exists for message ({0:X4}) on this control", msg));
        }

        public static void UnhookWndProc(Control ctl, bool disposing)
        {
            HookedProcInformation hpi = null;
            IntPtr ctl_Handle1 = IntPtr.Zero;
            try
            {
                if (ctl.IsDisposed) return;
                if (ctl.Handle == IntPtr.Zero) return;
                ctl_Handle1 = ctl.Handle;
            }
            catch (ObjectDisposedException odex)
            {
                Debug.WriteLine(odex.ToString());
            }
            // Control was disposed
            if (ctl_Handle1 == IntPtr.Zero) return;
            //
            if (ctlDict.ContainsKey(ctl))
            {
                hpi = ctlDict[ctl];
            }
            else if (hwndDict.ContainsKey(ctl_Handle1))
            {
                hpi = hwndDict[ctl.Handle];
            }
            if (hpi == null) throw new ArgumentException("No hook exists for this control");

            // If we found our HookedProcInformation in ctlDict and we are 
            // disposing remove it from ctlDict. 
            if (ctlDict.ContainsKey(ctl) && disposing) ctlDict.Remove(ctl);

            // If we found our HookedProcInformation in hwndDict, remove it 
            // and if we are not disposing stick it in ctlDict. 
            if (hwndDict.ContainsKey(ctl.Handle))
            {
                hpi.Unhook();
                hwndDict.Remove(ctl.Handle);
                if (!disposing) ctlDict[ctl] = hpi;
            }
        }

        class HookedProcInformation
        {

            public Dictionary<uint, WndProcCallback> messageMap;
            private IntPtr oldWndProc;
            private Win32.WndProc newWndProc;
            private Control control;
            private bool replicate;
            public bool Replicate
            {
                get { return replicate; }
            }
            public HookedProcInformation(Control ctl, Win32.WndProc wndproc, bool replic)
            {
                control = ctl;
                newWndProc = wndproc;
                replicate = replic;
                messageMap = new Dictionary<uint, WndProcCallback>();
            }
            public HookedProcInformation(Control ctl, Win32.WndProc wndproc)
                : this(ctl, wndproc, false)
            {

            }
            public void SetHook()
            {
                IntPtr hwnd = control.Handle;
                if (hwnd == IntPtr.Zero) throw new InvalidOperationException("Handle for control has not been created");

                oldWndProc = Win32.SetWindowLong(hwnd, Win32.GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(newWndProc));
            }

            public void Unhook()
            {
                IntPtr hwnd = control.Handle;
                if (hwnd == IntPtr.Zero)
                {
                    throw new InvalidOperationException("Handle for control has not been created");
                }

                Win32.SetWindowLong(hwnd, Win32.GWL_WNDPROC, oldWndProc);
            }

            public int CallOldWindowProc(IntPtr hwnd, uint msg, uint wParam, int lParam)
            {
                return Win32.CallWindowProc(oldWndProc, hwnd, msg, wParam, lParam);
            }
        }
    }
}

This is all that I have done. If you find any miss, let me know.

regards,

antonio H Lopes

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM