繁体   English   中英

将 Window 脱钩到原来的 State

[英]Unhook Window into its original State

我使用以下代码将 window 挂接到面板中:

SetParent(win, pnlApp.Handle);
SetWindowLong(win, GWL_STYLE, WS_VISIBLE);
MoveWindow(win, 0, 0, pnlApp.Width, pnlApp.Height, true);

其中win是 Window 句柄,作为IntPtr 在这里想想记事本,它会很好地钩入一个面板。
但是当我尝试使用以下代码释放(取消挂钩)它时:

SetParent(win, (IntPtr)0);

它显示没有 Window 框架,我的意思是它会再次发布到桌面。 但它没有任何 Window 框架。

如何解决这个问题?

关于问题中的代码:

  • SetWindowLong()应替换为SetWindowLongPtr() - 请参阅文档中的警告 后者在调用代码需要时调用前者。

  • 需要调用GetWindowLongPtr()获取当前的Window Styles,然后根据需要添加或删除Styles; 存储原始值:用于恢复之前的状态。
    ► 在示例中,删除了WS_SYSMENU样式,因此 Window 不会显示系统菜单和通常位于标题中的所有按钮。 这只是一个例子,看看它是如何工作的(它可能不适用于所有 Windows)。

  • SetParent()返回前一个 Parent 的句柄。 存储此值,将需要将 Window 恢复为其先前的所有者,无论它是什么。 如果 Window 是顶级 Window,则先前的 Parent似乎是 Desktop,因此您期望IntPtr.Zero 可能不是,您可以获得一个不是IntPtr.Zero的句柄。 只需存储返回的值,如果您有兴趣,请查看它是什么:)

  • 您应该检查GetWindowLongPtr()SetWindowLongPtr()的返回值:如果它是0 ,那么有一个错误。 您可以使用Marshal.GetLastWin32Error()来获取错误代码。 请注意, SetWindowLongPtr()不会清除错误代码,因此您必须自己清除它,调用SetLastError(0)

  • 您可以使用MoveWindow()将 Windows 重新定位在新父级的范围内; 这可能不是必需的。 无论如何,我建议改为调用SetWindowPos() ,您有更多选择。 请参阅此处的代码。

免责声明:请记住 Raymond Chen 的博客文章中的内容:
拥有跨进程父/子或所有者/拥有的 window 关系是否合法
换句话说,这只是因为你问的事情:)


设置这些字段(或任何合适的):

  • windowdHwnd是 Window 的句柄 to re-parent
  • oldParent是前一个 Parent 的句柄,由SetParent()返回
  • oldStyles将存储上一个 Window 的 Styles,由GetWWindowLongPtr()返回
IntPtr windowdHwnd = IntPtr.Zero;
IntPtr oldParent = (IntPtr)(-1);
int oldStyles = 0;
// [...]

当你有你关心的 Window 的 Handle 时,将windowdHwnd设置为这个值。 之后调用此代码(它可能是一个方法,传递 Window 句柄和将成为新父级的容器控件 - 这里是一个名为somePanel的控件)。

// Already parented, resets the previous styles, clean up and return
if (windowdHwnd != IntPtr.Zero && oldParent != (IntPtr)(-1)) {
    NativeMethods.SetParent(windowdHwnd, oldParent);
    NativeMethods.SetWindowLongPtr(windowdHwnd, NativeMethods.GWL_Flags.GWL_STYLE, new IntPtr(oldStyles));
    windowdHwnd = IntPtr.Zero;
    oldParent = (IntPtr)(-1);
    return;
}

// Store the existing Styles, to restore when the Window is dismissed
oldStyles = NativeMethods.GetWindowLongPtr(windowdHwnd, NativeMethods.GWL_Flags.GWL_STYLE);
if (oldStyles == IntPtr.Zero) {
    int error = Marshal.GetLastWin32Error();  // Show the error code or throw an exception
    return;
}

// Removes the System Menu from the Window: it will also remove the Buttons from the Caption
int newStyle = oldStyles.ToInt32()^ (int)NativeMethods.WinStyles.WS_SYSMENU;

NativeMethods.SetLastError(0);
// Sets the new Styles
IntPtr result = NativeMethods.SetWindowLongPtr(windowdHwnd, NativeMethods.GWL_Flags.GWL_STYLE, (IntPtr)newStyle);
if (result == IntPtr.Zero) {
    int error = Marshal.GetLastWin32Error();  // Show the error code or throw an exception
    return;
}

oldParent = NativeMethods.SetParent(windowdHwnd, somePanel.Handle);

// Repositions the Window and shows it, if needed
var flags = NativeMethods.SWP_Flags.SWP_ASYNCWINDOWPOS | NativeMethods.SWP_Flags.SWP_SHOWWINDOW;
NativeMethods.SetWindowPos(windowdHwnd, IntPtr.Zero, 0, 0, somePanel.Width, somePanel.Height, flags);

你可以写(这只是删除):

int newStyle = oldStyles &~(int)NativeMethods.WinStyles.WS_SYSMENU;

而不是(这会打开/关闭):

int newStyle = oldStyles ^ (int)NativeMethods.WinStyles.WS_SYSMENU;

NativeMethods class:

using System.Runtime.InteropServices;

public class NativeMethods
{
    [Flags]
    public enum SWP_Flags : uint
    {
        /// <summary>Retains the current size (ignores the cx and cy parameters).</summary>
        SWP_NOSIZE = 0x0001,
        /// <summary>Retains the current position (ignores X and Y parameters).</summary>
        SWP_NOMOVE = 0x0002,
        /// <summary>Retains the current Z order (ignores the hWndInsertAfter parameter).</summary>
        SWP_NOZORDER = 0x0004,
        /// <summary>Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to
        /// the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent
        /// window uncovered as a result of the window being moved. When this flag is set, the application must
        /// explicitly invalidate or redraw any parts of the window and parent window that need redrawing.</summary>
        SWP_NOREDRAW = 0x0008,
        /// <summary>Does not activate the window. If this flag is not set, the window is activated and moved to the
        /// top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter
        /// parameter).</summary>
        SWP_NOACTIVATE = 0x0010,
        /// <summary>Draws a frame (defined in the window's class description) around the window.</summary>
        SWP_DRAWFRAME = 0x0020,
        /// <summary>Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to
        /// the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE
        /// is sent only when the window's size is being changed.</summary>
        SWP_FRAMECHANGED = 0x0020,
        /// <summary>Displays the window.</summary>
        SWP_SHOWWINDOW = 0x0040,
        /// <summary>Hides the window.</summary>
        SWP_HIDEWINDOW = 0x0080,
        /// <summary>Discards the entire contents of the client area. If this flag is not specified, the valid
        /// contents of the client area are saved and copied back into the client area after the window is sized or
        /// repositioned.</summary>
        SWP_NOCOPYBITS = 0x0100,
        /// <summary>Does not change the owner window's position in the Z order.</summary>
        SWP_NOOWNERZORDER = 0x0200,
        /// <summary>Same as the SWP_NOOWNERZORDER flag.</summary>
        SWP_NOREPOSITION = 0x0200,
        /// <summary>Prevents the window from receiving the WM_WINDOWPOSCHANGING message.</summary>
        SWP_NOSENDCHANGING = 0x0400,
        /// <summary>Internal use.</summary>
        SWP_NOCLIENTSIZE = 0x0800,
        /// <summary>Internal use.</summary>
        SWP_NOCLIENTMOVE = 0x1000,
        /// <summary>Prevents generation of the WM_SYNCPAINT message.</summary>
        SWP_DEFERERASE = 0x2000,
        /// <summary>If the calling thread and the thread that owns the window are attached to different input queues,
        /// the system posts the request to the thread that owns the window. This prevents the calling thread from
        /// blocking its execution while other threads process the request.</summary>
        SWP_ASYNCWINDOWPOS = 0x4000
    }

    [Flags]
    public enum WinStyles : uint
    {
        WS_BORDER = 0x00800000,                     //The window has a thin-line border.
        WS_CAPTION = 0x00C00000,                    //The window has a title bar (includes the WS_BORDER style).
        WS_CHILD = 0x40000000,                      //The window is a child window. A window with this style cannot have a menu bar. This style cannot be used with the WS_POPUP style.
        WS_CHILDWINDOW = 0x40000000,                //Same as the WS_CHILD style.
        WS_CLIPCHILDREN = 0x02000000,               //Excludes the area occupied by child windows when drawing occurs within the parent window. This style is used when creating the parent window.
        WS_CLIPSIBLINGS = 0x04000000,               //Clips child windows relative to each other; that is, when a particular child window receives a WM_PAINT message, the WS_CLIPSIBLINGS style clips all other overlapping child windows out of the region of the child window to be updated. If WS_CLIPSIBLINGS is not specified and child windows overlap, it is possible, when drawing within the client area of a child window, to draw within the client area of a neighboring child window.
        WS_DISABLED = 0x08000000,                   //The window is initially disabled. A disabled window cannot receive input from the user. To change this after a window has been created, use the EnableWindow function.
        WS_DLGFRAME = 0x00400000,                   //The window has a border of a style typically used with dialog boxes. A window with this style cannot have a title bar.
        WS_GROUP = 0x00020000,                      //The window is the first control of a group of controls. The group consists of this first control and all controls defined after it, up to the next control with the WS_GROUP style. The first control in each group usually has the WS_TABSTOP style so that the user can move from group to group. The user can subsequently change the keyboard focus from one control in the group to the next control in the group by using the direction keys.
                                                    //You can turn this style on and off to change dialog box navigation. To change this style after a window has been created, use the SetWindowLong function.
        WS_HSCROLL = 0x00100000,                    //The window has a horizontal scroll bar.
        WS_ICONIC = 0x20000000,                     //The window is initially minimized. Same as the WS_MINIMIZE style.
        WS_MAXIMIZE = 0x01000000,                   //The window is initially maximized.
        WS_MAXIMIZEBOX = 0x00010000,                //The window has a maximize button. Cannot be combined with the WS_EX_CONTEXTHELP style. The WS_SYSMENU style must also be specified.
        WS_MINIMIZE = 0x20000000,                   //The window is initially minimized. Same as the WS_ICONIC style.
        WS_MINIMIZEBOX = 0x00020000,                //The window has a minimize button. Cannot be combined with the WS_EX_CONTEXTHELP style. The WS_SYSMENU style must also be specified.
        WS_OVERLAPPED = 0x00000000,                 //The window is an overlapped window. An overlapped window has a title bar and a border. Same as the WS_TILED style.
        WS_OVERLAPPEDWINDOW = WS_OVERLAPPED |       //The window is an overlapped window. Same as the WS_TILEDWINDOW style.
                              WS_CAPTION |
                              WS_SYSMENU |
                              WS_THICKFRAME |
                              WS_MINIMIZEBOX |
                              WS_MAXIMIZEBOX,
        WS_POPUP = 0x80000000,                      //The windows is a pop-up window. This style cannot be used with the WS_CHILD style.
        WS_POPUPWINDOW = WS_POPUP |                 //The window is a pop-up window. The WS_CAPTION and WS_POPUPWINDOW styles must be combined to make the window menu visible.
                         WS_BORDER |
                         WS_SYSMENU,
        WS_SIZEBOX = 0x00040000,                    //The window has a sizing border. Same as the WS_THICKFRAME style.
        WS_SYSMENU = 0x00080000,                    //The window has a window menu on its title bar. The WS_CAPTION style must also be specified.
        WS_TABSTOP = 0x00010000,                    //The window is a control that can receive the keyboard focus when the user presses the TAB key. Pressing the TAB key changes the keyboard focus to the next control with the WS_TABSTOP style.
                                                    //You can turn this style on and off to change dialog box navigation. To change this style after a window has been created, use the SetWindowLong function. For user-created windows and modeless dialogs to work with tab stops, alter the message loop to call the IsDialogMessage function.
        WS_THICKFRAME = 0x00040000,                 //The window has a sizing border. Same as the WS_SIZEBOX style.
        WS_TILED = 0x00000000,                      //The window is an overlapped window. An overlapped window has a title bar and a border. Same as the WS_OVERLAPPED style.
        WS_TILEDWINDOW = WS_OVERLAPPED |            //The window is an overlapped window. Same as the WS_OVERLAPPEDWINDOW style.
                         WS_CAPTION |
                         WS_SYSMENU |
                         WS_THICKFRAME |
                         WS_MINIMIZEBOX |
                         WS_MAXIMIZEBOX,
        WS_VISIBLE = 0x10000000,                   //The window is initially visible. This style can be turned on and off by using the ShowWindow or SetWindowPos function.
        WS_VSCROLL = 0x00200000,                   //The window has a vertical scroll bar.
    }

    public enum GWL_Flags : int
    {
        GWL_USERDATA = -21,
        GWL_EXSTYLE = -20,
        GWL_STYLE = -16,
        GWL_ID = -12,
        GWLP_HWNDPARENT = -8,
        GWLP_HINSTANCE = -6,
        GWL_WNDPROC = -4,
        DWLP_MSGRESULT = 0x0,
        DWLP_DLGPROC = 0x4,
        DWLP_USER = 0x8
    }


    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern IntPtr GetWindowLongPtr(IntPtr hWnd, GWL_Flags nIndex);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern IntPtr SetWindowLongPtr(IntPtr hWnd, GWL_Flags nIndex, IntPtr dwNewLong);

    [DllImport("user32.dll", SetLastError = true)]
    internal static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

    [DllImport("user32.dll", SetLastError = true)]
    internal static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP_Flags uFlags);

    [DllImport("kernel32.dll")]
    internal static extern void SetLastError(uint dwErrCode);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM