关于问题中的代码:
-
设置窗口长() https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowlongw应替换为设置窗口长指针() https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowlongptrw- 参见warning在文档中。后者在调用代码需要时调用前者。
-
你需要打电话获取窗口长指针() https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowlongptrw获取当前的窗口样式,然后根据需要添加或删除样式;存储原始值:它将用于恢复之前的状态。
► 在示例中,WS_SYSMENU
样式被删除,因此窗口将不会显示系统菜单和通常位于标题中的所有按钮。这只是一个例子,看看它是如何工作的(它可能不适用于所有 Windows)。
-
设置父级() https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setparent返回前一个父级的句柄。存储此值,将需要将窗口恢复到其先前的所有者(无论是什么)。如果该窗口是顶级窗口,则前一个父窗口appears是桌面,所以你可能会期望IntPtr.Zero
。可能不是,你可以获得一个不是的句柄IntPtr.Zero
。只要存储返回的值,看看它是什么,如果你有兴趣:)
-
您应该检查两者的返回值GetWindowLongPtr()
and SetWindowLongPtr()
: 如果它是0
,然后出现错误。您可以使用Marshal.GetLastWin32Error() https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.getlastwin32error获取错误代码。注意SetWindowLongPtr()
不会清除错误代码,因此您必须自己清除它,调用设置最后一个错误(0) https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-setlasterror.
-
您可以使用移动窗口() https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-movewindow将 Windows 重新定位在新 Parent 的边界内;我建议打电话设置窗口位置() https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowpos相反,你有更多的选择。请参阅此处的代码。
Disclaimer: keep in mind what's in Raymond Chen's blog post:
Is it legal to have a cross-process parent/child or owner/owned window relationship https://devblogs.microsoft.com/oldnewthing/20130412-00/?p=4683
In other words, it's a just because you asked thing :)
设置这些字段(或任何合适的字段):
-
windowdHwnd
是窗口的句柄重新成为父母
-
oldParent
是前一个父级的句柄,由以下方法返回SetParent()
-
oldStyles
将存储以前的窗口样式,由GetWindowLongPtr()
IntPtr windowdHwnd = IntPtr.Zero;
IntPtr oldParent = (IntPtr)(-1);
int oldStyles = 0;
// [...]
当您拥有您关心的窗口句柄时,设置windowdHwnd
到这个值。之后调用此代码(它可以是一个方法,传递窗口句柄和将成为新父级的容器控件 - 这里是一个名为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);
}