我正在尝试使用System.Runtime.InteropServices.SafeHandle
的子类来管理指向Win32 GUI对象的指针(即HWND
和HMENU
)。然后我使用这些句柄在C#中实现基于Win32的GUI库。在此过程中,我创建一个菜单并将其分配给窗口。但是,假设我没有保留包含HMENU
的SafeHandle,因此在拥有它的窗口之前它是垃圾收集的。当他们的SafeHandles消失时,我不能简单地销毁所有HMENU
指针,因为这样的事情发生了:
HMENU
并将其分配到SafeHandle
的子类中,该子类会自动调用DestroyMenu()
。HWND
,并使用HMENU
Win32 API调用为其分配SetMenu()
。HWND
现在保留HMENU
,所以不应该销毁它(通过DestroyMenu()
),直到拥有它的HWND
最早被销毁。< / LI>
HMENU
包装在SafeHandle中,所以GC很快会解除分配SafeHandle,从而销毁HMENU
,而HWND
仍会引用它。 / LI>
我能做些什么来确保HMENU
只要有需要就会保持不变,但是一旦拥有HWND
GCed,它仍会被销毁?我查看this question,这几乎是理想的,除了它讨论使用内置引用计数的本机库。 Win32没有 - 句柄存在或被销毁。我考虑使用类似SafeHandle
的类添加我自己的引用计数,但由于并非所有引用HMENU
的程序的所有部分(即Win32)都可以访问我参考计数班。这是我用例的问题吗?我是否可以/应该实现这样的API包装器?
答案 0 :(得分:0)
简短的回答是否定的,在不再需要HMENU之前,没有办法让Win32 API保持对.net对象的引用。
你可以做的是用自己的类包装HWND,并在你的SetMenu上保存你对象内的引用 - 但这不会起作用,因为:
不允许从终结器中销毁GDI对象,因为终结器是从GC中的专用线程调用的,并且只允许从创建它的同一线程触摸GDI对象(它将排序 - 大部分时间都在工作,但是你以不支持的方式使用API)
从终结器中释放HWND(即使它被允许)将使窗口在完全不可预测的时间从屏幕上消失
这适用于引用计数的本机框架,因为与GC不同,发布引用是100%可预测和可控制的。
(基本上,WinForms的设计方式是出于某种原因)