簡體   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