C# 从控件创建父窗体WndProc的子类
我正在将自定义MenuStrip控件集成到另一个.NET应用程序中。MenuStrip工作正常,但有一个焦点问题。如果承载MenuStrip的表单没有焦点,用户需要单击两次-一次激活表单,另一次选择菜单项。主机窗体是单独的.NET应用程序的一部分,我无法修改它。我只能修改控件的源代码 我发现了一个重写表单WndProc方法的方法,但我没有WinForm的源代码访问权限,也无法重新编译宿主应用程序和表单C# 从控件创建父窗体WndProc的子类,c#,winforms,user-controls,subclass,C#,Winforms,User Controls,Subclass,我正在将自定义MenuStrip控件集成到另一个.NET应用程序中。MenuStrip工作正常,但有一个焦点问题。如果承载MenuStrip的表单没有焦点,用户需要单击两次-一次激活表单,另一次选择菜单项。主机窗体是单独的.NET应用程序的一部分,我无法修改它。我只能修改控件的源代码 我发现了一个重写表单WndProc方法的方法,但我没有WinForm的源代码访问权限,也无法重新编译宿主应用程序和表单 有没有办法对控件的父窗体进行子类化,以便它在未聚焦时自动激活父窗体?我可以使用Containe
有没有办法对控件的父窗体进行子类化,以便它在未聚焦时自动激活父窗体?我可以使用ContainerControl.ParentForm获取对宿主窗体的引用,但是在生产环境中父窗体返回null,我仍然需要找到解决方案。我将NewWndProc处理程序放在try/catch中,以防它抛出任何异常,尽管我不确定它可能抛出什么(如果有的话)。我可能只能使用Win32函数,而不能使用Form.Focused和Form.Activate().NET方法。无论如何,代码如下:
public class FocusFormWrapper
{
#region DllImport
public const int GWL_WNDPROC = (-4);
public const UInt32 WM_CLOSE = 0x0010;
public const UInt32 WM_PARENTNOTIFY = 0x0210;
public delegate IntPtr WndProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", SetLastError = true)]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr newWndProc);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string _ClassName, string _WindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetForegroundWindow(IntPtr hWnd);
#endregion DllImport
private Form myForm = null;
private IntPtr hWndTarget = IntPtr.Zero;
private IntPtr oldWndProc = IntPtr.Zero;
private WndProcDelegate newWndProc;
private FocusFormWrapper()
{
}
public FocusFormWrapper(Form sourceForm)
{
if (sourceForm == null)
throw new ArgumentNullException("sourceForm");
if (!IsWindow(sourceForm.Handle))
throw new ArgumentException("sourceForm IsWindow failed");
myForm = sourceForm;
hWndTarget = myForm.Handle;
AddSubclass();
}
~FocusFormWrapper()
{
RemoveSubclass();
myForm = null;
newWndProc = null;
}
private int AddSubclass()
{
int result = -1;
if (myForm != null && newWndProc == null)
{
newWndProc = new WndProcDelegate(NewWndProc);
oldWndProc = GetWindowLong(hWndTarget, GWL_WNDPROC);
result = SetWindowLong(hWndTarget, GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(newWndProc));
}
return result;
}
public int RemoveSubclass()
{
int result = -1;
if (myForm != null && newWndProc != null)
{
result = SetWindowLong(hWndTarget, GWL_WNDPROC, oldWndProc);
newWndProc = null;
}
return result;
}
public IntPtr NewWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
try
{
if (msg == WM_PARENTNOTIFY && !myForm.Focused)
{
// Make this form auto-grab the focus when menu/controls are clicked
myForm.Activate();
}
if (msg == WM_CLOSE)
{
RemoveSubclass();
}
}
catch
{
}
return CallWindowProc(oldWndProc, hWnd, msg, wParam, lParam);
}
}