【发布时间】:2013-07-20 01:34:24
【问题描述】:
我有一个TextBox,它不能用新类重新定义,这样我就可以过滤WndProc 中的一些消息。所以我必须使用win32函数SetWindowLong将TextBox的默认Window proc替换为我自己的Window Proc。所以我可以过滤该Window proc 中的一些消息。我已经成功完成了替换。可以在我的Window proc 中过滤消息。但是它并不完整,因为不一致的异常InvalidOperationException(这表示我的文本框是从创建它的线程之外的线程访问的)。奇怪的是,我的表单由设计师自动创建的被覆盖的受保护方法Dispose() 中的异常突出显示了base.Dispose(disposing); 行。
这是我替换为默认窗口过程的代码:
[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 中输入一些字符,但是继续输入或尝试使用鼠标选择文本...可能会引发我上面提到的异常。我没有找到任何有关此问题的文档。如果myTextBox.InvokeRequired = true;,我也尝试使用Invoke 在我自己的MyWndProcFunc(...) 中调用CallWindowProc(...),但没有区别。
你能深入研究这个问题来帮助我吗?使用我发布的代码可以轻松重现该问题。谢谢!
更新
我想明确一点,我的目的是要替换不能被继承或属于另一个应用程序的TextBox 的默认窗口进程。但是上面的代码是用标准的 .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()
【问题讨论】:
-
我已经在 Windows Vista 和 7、32 位和 64 位上进行了尝试,但到目前为止我无法重现该错误。你能发布堆栈跟踪吗?
-
@cokeman19 你的意思是你成功运行了代码吗?太棒了。我正在使用 Windows 7 - Ultimate 64 位。我更新了堆栈跟踪,请参阅。
-
@cokeman19 顺便说一句,请仔细阅读我的问题,您必须尝试输入足够长的字符才能引发异常。使用鼠标选择文本是引发异常的最快方法。谢谢!
-
是的,它对我来说运行成功。我同时单击并输入文本框,但无济于事。看起来您的表单肯定正在被处理。对我来说,这说明某处发生了异常。几个想法。 1)打开VS中的选项以停止所有抛出的异常。 2) 在您的 SetWindowLong 声明中,将您的 IntPtr 参数更改为 HandleRef。
-
@cokeman19 奇怪的是它对你有用。我尝试将
IntPtr替换为HandleRef,如下所示:HandleRef hwnd = new HandleRef(myFormInstance, IntPtr_handle);,但它仍然不起作用。
标签: c# winforms winapi pinvoke