Windows messge is lose after hook count over 31
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:
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
- Create a winform .net framework solution.
- Place serval MyTextBox (code is above)controls, count is over 31.
- Create a button, when click a button, show a new windows form
- 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!