当前位置:  开发笔记 > 编程语言 > 正文

.NET Winforms:运行时可以从我下面处理表单的句柄吗?

如何解决《.NETWinforms:运行时可以从我下面处理表单的句柄吗?》经验,为你挑选了0个好方法。

目前申报的SendMessage了在PInvoke.net是:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessage(HandleRef hWnd, uint Msg, 
      IntPtr wParam, IntPtr lParam);

注意: hWnd不再是IntPtr,并且已被HandleRef替换.给出了一个非常松散的变化解释:

您可以将"hWnd"替换为"IntPtr"而不是"HandleRef".但是,您冒这样做的风险 - 它可能会导致您的代码因竞争条件而崩溃..NET运行时可以并且将会从您的消息下处理窗口句柄 - 导致各种令人讨厌的问题!

维基有人提出了一个后续问题:

问题:最后一个问题不能用编组来解决,特别是固定吗?

有人回答说:

答:您可以在SendMessage()之后使用GC.KeepAlive(),并将Form对象作为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返回,表单的句柄无效.无论采用何种技术,情况都是如此 - 如果表格不在某个范围内,则无效使用.

我不同意(todo link guy),因为表格会一直存在,直到收到所有发送消息.CLR不知道谁可能已经获得了窗体的窗口句柄,并且无法知道将来可以调用SendMessage()的人.

换句话说,我无法想象:

IntPtr hWnd = this.Handle;

现在将防止被垃圾收集.


更新二

我无法想象周围有一个窗口处理会使表单不被垃圾收集.即:

Clipboard.AsText = this.Handle.ToString();
IntPtr theHandle = (IntPtr)(int)Clipboard.AsText;

回答

但这些都是相关的 - 最初的问题仍然是:

运行时可以从我下面处理一个表单的句柄吗?

事实证明,答案是否定的.运行时不会从我下面处理一个表单.这配置不再被引用的形式-但未引用的形式是不是在我之下."在我之下"意味着我可以参考表格.

另一方面,Form对象的底层Windows窗口句柄可以从我下面销毁(实际上它怎么可能 - 窗口句柄不是引用计数 - 它们也不应该是):

IntPtr hwnd = this.Handle;
this.RightToLeft = RightToLeft.Yes;
//hwnd is now invalid

同样重要的是要注意HandleRef无法帮助防止因在Windows窗口句柄周围创建对象包装器而导致的问题:

原因1 如果一个表单对象因为没有对它的引用而被销毁 - 那么你试图与权限不再存在的表单进行交谈就是愚蠢的.仅仅因为GC还没有找到它但却没有让你变得聪明 - 这让你很幸运.HandleRef是一个黑客,可以保持对表单的引用.而不是使用:

HandleRef hr = new HandleRef(this, this.Handle);
DoSomethingWithHandle(this.Handle);

你可以轻松使用:

Object o = this;
DoSomethingWithHandle(this.Handle);

Reason 2 HandleRef不会阻止表单重新创建它的底层窗口句柄,例如:

HandleRef hr = new HandleRef(this, this.Handle);
this.RightToLeft = RightToLeft.Yes;
//hr.Hande is now invalid

因此虽然P/Invoke上SendMessage的原始修饰符确实指出了问题,但他的解决方案并不是解决方案.

推荐阅读
小白也坚强_177
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有