0

我有一个TextBox不能用新类重新定义的,这样我就可以在WndProc. 所以我必须使用win32函数来替换我自己SetWindowLong的默认Window proc值。所以我可以过滤其中的一些消息。我已经成功完成了替换。消息可以在我的. 然而,由于不一致的异常(这表示我的文本框是从创建它的线程之外的线程访问的),它并不完整。奇怪的是,异常突出显示了由设计器自动创建的表单的覆盖保护方法中的行。TextBoxWindow ProcWindow procWindow procInvalidOperationExceptionbase.Dispose(disposing);Dispose()

这是我替换为默认窗口过程的代码:

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

表单开始正常,我可以在我的 中输入一些字符TextBox,但是继续输入或尝试使用鼠标选择文本...可以引发我上面提到的异常。我没有找到任何有关此问题的文档。我也尝试过使用我自己的Invoke电话,但没有区别。CallWindowProc(...)MyWndProcFunc(...)myTextBox.InvokeRequired = true;

你能深入研究这个问题来帮助我吗?使用我发布的代码可以轻松重现该问题。谢谢!

更新

我想明确一点,我的目的是要替换TextBox不能被继承或属于另一个应用程序的默认窗口 proc。但是上面的代码是用标准的 .NET 测试的TextBox。这是在我的项目中应用之前测试的第一步。这是堆栈跟踪:

  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()
4

2 回答 2

2
    [DllImport("user32")]
    private static extern int CallWindowProc(...)

至少有两个原因没有人可以从您的示例代码中获得重现。只有设置 TextBox.AutoCompleteMode 属性时,才会发生调用堆栈中显示的崩溃。当您将程序作为 64 位进程运行时,您的代码中的错误只会字节,大多数 SO 用户将使用 x86 的默认平台目标设置。

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

而不是使用 pinvoke,永远存在这样的微妙错误的风险,更安全的方法是从 NativeWindow 派生您自己的类:

    private class MyTextBoxWindow : NativeWindow {
        protected override void WndProc(ref Message m) {
            // Customizations here
            //...
            base.WndProc(ref m);
        }
    }

并在您的 Load 事件处理程序中使用其 AssignHandle() 方法。当您收到 WM_NCDESTROY 消息时,您应该调用 ReleaseHandle()。

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

于 2013-07-20T11:02:03.167 回答
0

如果此问题与库中的文本框隔离,则该库中的某些内容似乎发生在第二个线程上,据我猜测,该线程正在引发异常并最终触发处置。

我建议查看库的源代码并尝试确定是否发生了任何多线程。如果您无权访问源代码,则始终可以使用ILSpy,它可以反编译以及调试已编译的程序集。

于 2013-07-20T04:03:49.913 回答