Windows messge is lose after hook count over 31

Chen YingZuo(Aron) 1 Reputation point
2022-07-13T04:03:15.887+00:00

I have a desktop application based on WinForm framework.

I created a custom control, this control use windows hook (https://learn.microsoft.com/en-us/windows/win32/winmsg/about-hooks) to accomplish some features.
My test project looks like this:
220159-pic1.png

I found when controls count is over 31, except the first 31 controls, other controls loose message.

Please follow this step:
First create a custom control "MyTextBox"

namespace TestWindowsHook  
{  
    internal class MyTextBox : TextBox  
    {  
        public MyTextBox()  
        {  
        }  
  
        public void StartHook()  
        {  
            var hook = new WindowHook(this);  
            hook.HookStart();  
        }  
  
        #region Hook  
  
        internal class WindowHook  
        {  
            public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);  
  
            [StructLayout(LayoutKind.Sequential)]  
            private struct CallWndProc  
            {  
                public IntPtr lParam;  
                public IntPtr wParam;  
                public int message;  
                public IntPtr hwnd;  
            }  
  
            public WindowHook(MyTextBox textBox)  
            {  
                _textBox = textBox;  
                _hookProc = new HookProc(ShowWindowHookProc);  
            }  
  
            private HookProc _hookProc;  
            private MyTextBox _textBox;  
            private IntPtr ShowWindowHookProc(int nCode, IntPtr wParam, IntPtr lParam)  
            {  
                if (nCode == 0)  
                {  
                    CallWndProc c = (CallWndProc)Marshal.PtrToStructure(lParam, typeof(CallWndProc));  
                    Message m = new Message();  
                    m.HWnd = c.hwnd;  
                    m.WParam = (IntPtr)c.wParam;  
                    m.LParam = (IntPtr)c.lParam;  
                    m.Msg = c.message;  
  
                    if (m.Msg == 24)  
                    {  
                        Debug.WriteLine($"{this._textBox.Name} get msg");  
                    }  
                }  
  
                return CallNextHookEx(_hHook, nCode, wParam, lParam);  
            }  
  
            private IntPtr _hHook = IntPtr.Zero;  
  
            public bool Installed  
            {  
                get  
                {  
                    return _hHook != IntPtr.Zero;  
                }  
            }  
            public void HookStart()  
            {  
                if (Installed)  
                {  
                    return;  
                }  
                _hHook = SetWindowsHookEx(4, _hookProc, IntPtr.Zero, GetCurrentThreadId());  
  
                if (_hHook == IntPtr.Zero)  
                {  
                    HookStop();  
                }  
            }  
  
            public void HookStop()  
            {  
                if (!Installed)  
                {  
                    return;  
                }  
  
                UnhookWindowsHookEx(_hHook);  
                _hHook = IntPtr.Zero;  
            }  
  
            [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto, SetLastError = true)]  
            public static extern IntPtr SetWindowsHookEx(int hookType, HookProc hookProc, IntPtr hInstance, int threadID);  
  
            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]  
            public static extern bool UnhookWindowsHookEx(IntPtr idHook);  
  
            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]  
            public static extern IntPtr CallNextHookEx(IntPtr hHook, int code, IntPtr wParam, IntPtr lParam);  
            [DllImport("kernel32.dll")]  
            static extern int GetCurrentThreadId();  
        }  
  
        #endregion  
    }  
}  

Then I test my controls followed by these steps

  1. Create a winform .net framework solution.
  2. Place serval MyTextBox (code is above)controls, count is over 31.
  3. Create a button, when click a button, show a new windows form
  4. Watch output message

This is my main form "Form1" code:

using System;  
using System.Collections.Generic;  
using System.ComponentModel;  
using System.Data;  
using System.Drawing;  
using System.Linq;  
using System.Text;  
using System.Threading.Tasks;  
using System.Windows.Forms;  
  
namespace TestWindowsHook  
{  
    public partial class Form1 : Form  
    {  
        public Form1()  
        {  
            InitializeComponent();  
            foreach (var t in GetAllTextBox())  
            {  
                t.StartHook();  
            }  
        }  
  
        private void button1_Click(object sender, EventArgs e)  
        {  
            Form2 form = new Form2();  
            form.Show();  
        }  
  
        private IEnumerable<MyTextBox> GetAllTextBox()  
        {  
            foreach (var control in this.Controls)  
            {  
                if (control is MyTextBox myTextBox)  
                {  
                    yield return myTextBox;  
                }  
            }  
        }  
    }  
}  
  

This is my test message output:

myTextBox1 get msg  
myTextBox2 get msg  
myTextBox3 get msg  
myTextBox4 get msg  
myTextBox5 get msg  
myTextBox10 get msg  
myTextBox9 get msg  
myTextBox8 get msg  
myTextBox7 get msg  
myTextBox6 get msg  
myTextBox15 get msg  
myTextBox14 get msg  
myTextBox13 get msg  
myTextBox12 get msg  
myTextBox11 get msg  
myTextBox20 get msg  
myTextBox19 get msg  
myTextBox18 get msg  
myTextBox17 get msg  
myTextBox16 get msg  
myTextBox25 get msg  
myTextBox24 get msg  
myTextBox23 get msg  
myTextBox22 get msg  
myTextBox21 get msg  
myTextBox30 get msg  
myTextBox29 get msg  
myTextBox28 get msg  
myTextBox27 get msg  
myTextBox26 get msg  
myTextBox35 get msg  

Only the first 31 controls get message, the rest controls loose message.
Is this a limitation or design? Thanks!

Windows Forms
Windows Forms
A set of .NET Framework managed libraries for developing graphical user interfaces.
1,904 questions
Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,657 questions
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.