在PInvoke.net上的SendMessage的当前声明是:
[DllImport("user32.dll",CharSet = CharSet.Auto,SetLastError = false)] static extern IntPtr SendMessage(HandleRef hWnd,uint Msg,IntPtr wParam,IntPtr lParam);
注意: hWnd不再是一个IntPtr ,并已被HandleRef取代。 给出了一个非常宽松的解释:
您可以将“hWnd”replace为“IntPtr”而不是“HandleRef”。 但是,您正在冒这样的风险 – 这可能会导致您的代码在竞争条件下崩溃。 .NET运行时可以并且将会把你的窗口句柄从你的消息中解脱出来,导致各种令人讨厌的问题!
有人维基跟进问题:
是一个迷你转储有用的.NETdebugging
System.IO.Directory.GetFiles返回与Windows XP Search Companion不同的结果
Windowssearch使用OLE DB sql字段
什么编程实践影响窗口句柄的数量?
问题:这个最后的问题不能用编组来解决,特别是固定?
有人回答说:
回答:您可以在SendMessage()和Form对象之后使用GC.KeepAlive()作为KeepAlive()的参数。
所有这些“把你的表格放在你的下面”对我来说似乎很奇怪。 SendMessage是一个同步调用。 它将不会返回,直到发送的消息已被处理。
这意味着一个表格句柄可以在任何时候被销毁。 例如:
private void DoStuff() { //get the handle IntPtr myHwnd = this.Handle; //Is the handle still valid to use? DoSomethingWithTheHandle(myHwnd); //handle might not be valid??? //fall off the function }
这意味着窗口句柄可以在我使用它的时间和方法结束的时间之间变成无效的。
更新一个
我理解一旦一个表格超出范围,这个句柄是无效的。 例如:
private IntPtr theHandle = IntPtr.Zero; private void DoStuff() { MyForm frm = new MyForm()) theHandle = frm.Handle; //Note i didn't dispose of the form. //But since it will be unreferenced once this method ends //it will get garbage collected,//making the handle invalid }
对我来说很明显,一旦DoStuff已经返回,表单的句柄是无效的。 无论采用什么技术,情况也是如此 – 如果表格不在某个范围内,则无效。
我会不同意(待办事项链接的人)的forms将坚持,直到所有发送消息已收到。 CLR不知道谁可能已经给我的窗体的窗口句柄,并且无法知道谁将来可以调用SendMessage()。
换句话说,我无法想象这个电话:
IntPtr hWnd = this.Handle;
现在将防止垃圾收集。
更新二
Clipboard.AsText = this.Handle.ToString(); IntPtr theHandle = (IntPtr)(int)Clipboard.AsText;
回答
但这些都是非法的问题 – 原来的问题依然是:
运行时可以从我的下面configuration一个窗体的句柄吗?
事实certificate,答案是否定的。 运行时不会从我的下面处理表单。 它会处理一个未被引用的表单 – 但是不被引用的表单不在我之下。 “在我之下”意味着我有一个参考的forms。
另一方面,Form对象的底层Windows窗口句柄可能会从我的下面被摧毁(实际上它怎么可能不是 – 窗口句柄不被引用计数 – 也不应该):
IntPtr hwnd = this.Handle; this.RightToLeft = RightToLeft.Yes; //hwnd is Now invalid
注意到HandleRef也不能帮助防止在Windows窗口句柄周围创build对象包装引起的问题。
原因1如果一个表单对象因为没有引用而被销毁 – 那么你只是试图与一个不应该存在权利的表单交谈。 只是因为GC没有得到它,但不会让你变得聪明 – 这会让你感到幸运。 HandleRef是一个黑客来保持对表单的引用。 而不是使用:
HandleRef hr = new HandleRef(this,this.Handle); DoSomethingWithHandle(this.Handle);
你可以很容易地使用:
Object o = this; DoSomethingWithHandle(this.Handle);
原因2 HandleRef不会阻止窗体重新创build它的底层窗口句柄,例如:
HandleRef hr = new HandleRef(this,this.Handle); this.RightToLeft = RightToLeft.Yes; //hr.Hande is Now invalid
所以虽然P / Invoke中的SendMessage的原始修饰符确实指出了一个问题,但他的解决scheme并不是解决scheme。
WinForm:与VS2010中的现有菜单合并ContextMenuStrip MenuItem
DotNetZip – 如何提取到工作目录
如何获得在Windows中的Z顺序?
在Linux上编译MonoDevelop 5.3时出错
在Mac和Windows上打开相同的.NET Core解决scheme
通常,当您调用SendMessage ,您正在从另一个线程或至少另一个与您的表单分离的组件中执行此操作。 我认为这一点是因为你有一个IntPtr在一个有效的窗口句柄,你不能认为它仍然是一个有效的。
假设你有这个班级:
class MyClass { IntPtr hwnd; public MyClass(IntPtr hwnd) { this.hwnd = hwnd; } ... private void DoStuff() { //nb we don't necessarily kNow if the handle is still valid DoSomethingWithTheHandle(hwnd); } }
和其他地方:
private void DoOtherStuff() { Form f = new Form(); mc = new MyClass(f.Handle); }
那么因为f已经超出了范围,它的dispose将最终被GC终结器调用。 这就是为什么你可能需要在这种情况下使用Gc.KeepAlive 。 f必须保持活着直到mc完成手柄。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。