为什么屏幕保护控制面板没有在窗体死亡时杀死它?
本文关键字:窗体 控制面板 屏幕保护 为什么 | 更新日期: 2023-09-27 18:19:21
使用我在CodeProject上找到的代码,我创建了一个屏幕保护程序。下面的表单是当用户选择我的屏幕保护程序时,我在控制面板中显示的一个小表单。
一切似乎都很好;表单正确地调整大小并在控制面板的正确位置绘制(它是空白的),随着CP移动等。但是当控制面板关闭(或者用另一个屏幕保护程序的迷你预览取代我的表单)时,我的应用程序并没有死。它只是挂在内存中。
我的表单没有收到表单关闭/关闭消息,或者可见性改变等。我对亲子关系的定义有错吗?
下面是相关代码。所有导入的WinAPI调用都返回预期的值,而GetLastError总是返回零,所以我认为这不是问题…
private void miniControlPanelForm_Load(object sender, EventArgs e)
{
// note that iphWnd is a class variable, passed to us by windows
// set our window style to WS_CHILD, so that our window is
// destroyed when parent window is destroyed.
// get the current window style, but with WS_CHILD set
IntPtr ip = new IntPtr();
int index = (int)NativeMethods.WindowLongFlags.GWL_STYLE | 0x40000000;
ip = NativeMethods.GetWindowLongPtr(this.Handle, index);
int error = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
// set that value as our current Style
object ohRef = new object();
HandleRef hRef = new HandleRef(ohRef, this.Handle);
IntPtr ip2 = new IntPtr();
int index2 = (int)NativeMethods.WindowLongFlags.GWL_STYLE;
ip2 = NativeMethods.SetWindowLongPtr(hRef, index2, ip);
error = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
// set the passed preview window as the parent of this window
IntPtr newOldParent = NativeMethods.SetParent(this.Handle, iphWnd);
error = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
//set our window's size to the size of our window's new parent
Rectangle ParentRect = new Rectangle();
NativeMethods.GetClientRect(iphWnd, ref ParentRect);
this.Size = ParentRect.Size;
//set our location at (0, 0)
this.Location = new Point(0, 0);
}
我有Application。在各种"窗体正在关闭"事件处理程序中退出,但它们永远不会被调用…
如果您正确地使窗体成为控制面板窗口的子窗体,那么所有这些问题都将消失。下面是我现在的做法,它在所有情况下都有效。
在表单中,添加以下内容,这将在创建时强制表单的窗口样式为WS_CHILD:
/// <summary>
/// Override CreateParams property so we can add "WS_CHILD" to
/// the Style each time it is queried during window creation.
/// </summary>
protected override CreateParams CreateParams
{
get
{
// get the base params and modify them
CreateParams cp = base.CreateParams;
cp.Style |= NativeMethods.WindowStyles.WS_CHILD;
return cp;
}
}
在接收控制面板的hWnd并创建表单的代码中,使用SetParent使表单成为控制面板的子窗体:
/// <summary>
/// Show the form in the little control panel preview window.
/// </summary>
/// <param name="hWnd">hwnd passed to us at launch by windows</param>
static void ShowMiniPreview(IntPtr hWnd)
{
if (NativeMethods.IsWindow(hWnd))
{
miniControlPanelForm preview = new miniControlPanelForm(hWnd);
IntPtr newParent = NativeMethods.SetParent(preview.Handle, hWnd);
// Set the size of the form to the size of the parent window (using the passed hWnd).
System.Drawing.Rectangle ParentRect = new System.Drawing.Rectangle();
bool fSuccess = NativeMethods.GetClientRect(hWnd, ref ParentRect);
// Set our size to new rect and location at (0, 0)
preview.Size = ParentRect.Size;
preview.Location = new System.Drawing.Point(0, 0);
// Show the form
preview.Show();
// and run it
Application.Run(preview);
}
}
请注意,"native emethods"是我的类与各种Win32方法和常数声明为pinvoke:
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
public static class WindowStyles
{
public static readonly Int32
WS_CHILD = 0x40000000;
}
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool GetClientRect(IntPtr hWnd, ref Rectangle rect);