C# 自定义WindowProc导致跨线程异常?

C# 自定义WindowProc导致跨线程异常?,c#,winforms,winapi,pinvoke,C#,Winforms,Winapi,Pinvoke,我有一个TextBox,不能用新类重新定义它,这样我就可以在WndProc中过滤一些消息。因此,我必须使用win32函数SetWindowLong将TextBox的默认windowproc替换为我自己的windowproc。所以我可以在窗口proc中过滤一些消息。我已经成功地完成了替换。可以在我的窗口过程中过滤消息。但是,由于不一致的异常InvalidOperationException(表示我的文本框是从创建它的线程以外的线程访问的),所以它不完整。奇怪的是异常突出显示了行base.Dispo

我有一个
TextBox
,不能用新类重新定义它,这样我就可以在
WndProc
中过滤一些消息。因此,我必须使用win32函数
SetWindowLong
TextBox
的默认
windowproc
替换为我自己的
windowproc
。所以我可以在
窗口proc
中过滤一些消息。我已经成功地完成了替换。可以在我的
窗口过程中过滤消息。但是,由于不一致的异常
InvalidOperationException
(表示我的文本框是从创建它的线程以外的线程访问的),所以它不完整。奇怪的是异常突出显示了行
base.Dispose(disposing)Dispose()
中的code>

以下是要替换为默认窗口进程的代码:

[DllImport("user32")]
private static extern IntPtr SetWindowLong(IntPtr hwnd, int nIndex, IntPtr proc);
[DllImport("user32")]
private static extern int CallWindowProc(IntPtr proc, IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam);
private delegate int MyWndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam);
public int MyWndProcFunc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam)
{
   //Call the default window proc to test
   //However even this can cause the exception after some keystrokes or mouse selection.
   return CallWindowProc(defProc, hwnd, msg, wParam, lParam);
}
IntPtr defProc;
public Form1(){
  InitializeComponent();
  Load += (s,e) => {
     defProc = SetWindowLong(myTextBox.Handle, -4, Marshal.GetFunctionPointerForDelegate(new MyWndProc(MyWndProcFunc)));//GWL_WNDPROC = -4
  };
}
表单开始正常,我可以在我的
文本框中键入一些字符,但是继续键入或尝试使用鼠标选择文本。。。可以引发我上面提到的异常。我没有发现任何关于这个问题的文档。我还尝试使用
Invoke
在我自己的
MyWndProcFunc(…)
中调用
CallWindowProc(…)
,如果
myTextBox.invokererequired=true但没有区别

你能深入研究这个问题帮我解决吗?用我发布的代码可以很容易地重现这个问题。谢谢

更新 我想说清楚,我的目的是要替换
文本框
的默认窗口进程,它不能被继承或属于另一个应用程序。但是上面的代码是用标准的.NET
TextBox
测试的。这是在我的项目中应用之前要测试的第一步。 以下是stacktrace:

  at System.Windows.Forms.Control.get_Handle()
  at System.Windows.Forms.TextBox.ResetAutoComplete(Boolean force)
  at System.Windows.Forms.TextBox.Dispose(Boolean disposing)
  at System.ComponentModel.Component.Dispose()
  at System.Windows.Forms.Control.Dispose(Boolean disposing)
  at System.Windows.Forms.ContainerControl.Dispose(Boolean disposing)
  at System.Windows.Forms.Form.Dispose(Boolean disposing)
  at WindowsFormsApplication1.Form1.Dispose(Boolean disposing) in C:\Users\iec\AppData\Local\Temporary Projects\WindowsFormsApplication1\Form1.Designer.cs:line 20
  at System.ComponentModel.Component.Dispose()
  at System.Windows.Forms.ApplicationContext.Dispose(Boolean disposing)
  at System.Windows.Forms.Application.ThreadContext.DisposeThreadWindows()

如果此问题与库中的textbox隔离,则该库中的某些内容可能发生在第二个线程上,根据我的最佳猜测,该线程正在引发异常并最终触发dispose

我建议查看库的源代码,并尝试确定是否存在任何多线程。如果您没有访问源代码的权限,则始终可以使用,它可以反编译和调试已编译的程序集

    [DllImport("user32")]
    private static extern int CallWindowProc(...)
至少有两个原因没有人可以从示例代码中获得复制。只有设置TextBox.AutoCompleteMode属性,才能发生调用堆栈中显示的崩溃。当您将程序作为64位进程运行时,代码中的错误将仅为字节,因此大多数用户将使用默认的平台目标设置x86

您对CallWindowProc(和MyWndProcFunc)的声明是错误的,返回值类型是IntPtr,而不是int。这可能会在64位模式下导致许多奇怪的问题,尽管句柄所有者测试失败不会在我的列表顶部

与使用pinvoke相比,使用pinvoke永远都有可能出现这样的细微错误,更安全的方法是从NativeWindow派生您自己的类:

    private class MyTextBoxWindow : NativeWindow {
        protected override void WndProc(ref Message m) {
            // Customizations here
            //...
            base.WndProc(ref m);
        }
    }
并在加载事件处理程序中使用其AssignHandle()方法。当您收到WM\u NCDESTROY消息时,应该调用ReleaseHandle()


当编辑控件属于另一个进程时,不要尝试执行此操作。窗口过程必须位于同一进程中。这需要向进程中注入DLL,但不能在C#中这样做,因为进程不会加载CLR来执行托管代码。本机代码是必需的,C是通常的选择。

我已经在Windows Vista&7、32和64位上试用过,但到目前为止,我无法重现错误。你能发布堆栈跟踪吗?@cokeman19你是说你成功运行了代码?太棒了。我使用的是Windows7-Ultimate 64位。我更新了堆栈跟踪,请参见。@cokeman19 BTW,请仔细阅读我的问题,您必须尝试键入足够长的字符以引发异常。使用鼠标选择文本是引发异常的最快方法。谢谢是的,它为我成功运行。我同时点击并输入文本框,但没有结果。看起来你的表格肯定被处理了。对我来说,这意味着某个地方正在发生异常。一些想法。1) 启用VS中的选项以停止所有抛出的异常。2) 在SetWindowLong声明中,将IntPtr参数更改为HandleRef。@cokeman19奇怪的是,它对您有效。我试着用如下方式替换
IntPtr
:HandleRef hwnd=newhandleref(myFormInstance,IntPtr\u handle)
但它仍然不起作用。然而,我刚刚在一个正常的
文本框
上进行了测试,如果测试成功,我将应用于实际的
文本框
,并在我的项目中使用该技术,该技术需要在另一个应用程序中连接到
文本框
。非常感谢,它现在可以工作了。首先,我将
int
更改为
IntPtr
,但它不起作用。这里的重点是应用程序目标是x64,更改为x86使其工作。事实上,我的文本框的
AutoCompleteMode
None
。您是否知道如何使其作为x64应用程序工作?关于
NativeWindow
,我没有找到任何
Attach()
以及
Detach()
方法,我也在
对象浏览器中搜索了
但没有找到任何东西。你能告诉我如何找到/访问它们吗?这是一个糟糕的问题,内存中的包装类太多了。我纠正了它。不,我不知道如何使它在64位模式下工作,如果我不能让你的复制程序炸弹。没有人可以。你是说即使应用程序目标是x64,也不能重现我的问题吗?我仍然对从
NativeWindow
派生的类感到困惑,它是否用于替换从
System.Windows.Forms.form
继承的表单?如果没有,我也不知道如何使用它,谢谢。很晚了