使用SetParent劫持Win32 PopUp窗体

来源:互联网 发布:哈尔滨知途 长江路130 编辑:程序博客网 时间:2024/06/04 00:33

SetParent说明: MSDN-SetParent()

这个方法的原型大概是这样的(WinUser.h):

WINUSERAPIHWNDWINAPISetParent(    _In_ HWND hWndChild,    _In_opt_ HWND hWndNewParent);

使用这个方法在劫持一些Style包含 WS_POPUP 的WIN32窗体时会出现劫持失败的情况(一般就是被劫持的窗体消失,指定的父窗体里没有出现子窗体)这是因为一般POPUP的窗体是不支持直接劫持的……MSDN里说的是 For compatibility reasons, SetParent does not modify the WS_CHILD or WS_POPUP window styles of the window whose parent is being changed.
能用SetParent劫持的窗体一般需要有 WS_CHILD (或者 WS_CHILDWINDOW 的样式,两者是完全一样的),在 WinUser.h 里,代码是这样的:

/** Window Styles*/...   #define WS_POPUP            0x80000000L#define WS_CHILD            0x40000000L...#define WS_POPUPWINDOW      (WS_POPUP          | \                             WS_BORDER         | \                             WS_SYSMENU)#define WS_CHILDWINDOW      (WS_CHILD)

设置窗体的样式,需要用到 GetWindowLongSetWindowLong ,两这个原型在 WinUser.h 中是这样的:

WINUSERAPILONGWINAPIGetWindowLongA(    _In_ HWND hWnd,    _In_ int nIndex);WINUSERAPILONGWINAPIGetWindowLongW(    _In_ HWND hWnd,    _In_ int nIndex);#ifdef UNICODE#define GetWindowLong  GetWindowLongW#else#define GetWindowLong  GetWindowLongA#endif // !UNICODEWINUSERAPILONGWINAPISetWindowLongA(    _In_ HWND hWnd,    _In_ int nIndex,    _In_ LONG dwNewLong);WINUSERAPILONGWINAPISetWindowLongW(    _In_ HWND hWnd,    _In_ int nIndex,    _In_ LONG dwNewLong);#ifdef UNICODE#define SetWindowLong  SetWindowLongW#else#define SetWindowLong  SetWindowLongA#endif // !UNICODE#ifdef _WIN64WINUSERAPILONG_PTRWINAPIGetWindowLongPtrA(    _In_ HWND hWnd,    _In_ int nIndex);WINUSERAPILONG_PTRWINAPIGetWindowLongPtrW(    _In_ HWND hWnd,    _In_ int nIndex);#ifdef UNICODE#define GetWindowLongPtr  GetWindowLongPtrW#else#define GetWindowLongPtr  GetWindowLongPtrA#endif // !UNICODEWINUSERAPILONG_PTRWINAPISetWindowLongPtrA(    _In_ HWND hWnd,    _In_ int nIndex,    _In_ LONG_PTR dwNewLong);WINUSERAPILONG_PTRWINAPISetWindowLongPtrW(    _In_ HWND hWnd,    _In_ int nIndex,    _In_ LONG_PTR dwNewLong);#ifdef UNICODE#define SetWindowLongPtr  SetWindowLongPtrW#else#define SetWindowLongPtr  SetWindowLongPtrA#endif // !UNICODE#else  /* _WIN64 */#define GetWindowLongPtrA   GetWindowLongA#define GetWindowLongPtrW   GetWindowLongW#ifdef UNICODE#define GetWindowLongPtr  GetWindowLongPtrW#else#define GetWindowLongPtr  GetWindowLongPtrA#endif // !UNICODE#define SetWindowLongPtrA   SetWindowLongA#define SetWindowLongPtrW   SetWindowLongW#ifdef UNICODE#define SetWindowLongPtr  SetWindowLongPtrW#else#define SetWindowLongPtr  SetWindowLongPtrA#endif // !UNICODE

MSDN-SetWindowLong()

在调用 SetWindowLong 之后,有时需要调用 SetWindowPos 来刷新一下窗体的缓存。这里有一点需要注意,MSDN中有如下描述:
If you have changed certain window data using SetWindowLong, you must call SetWindowPos for the changes to take effect. Use the following combination for uFlags: SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED.

C#中写C++函数原型的时候,类型映射一般是这样的规则:

C++ C# LPTR IntPtr int int long int/uint

在更改窗体样式的时候,会用到 WS_POPUP = 0x80000000L ,这个值C#用int装会吃警告,所以可以用uint装这个数。C#中函数原型以及代码可以如下书写:

const uint    WS_POPUP = 0x80000000,    WS_CHILD = 0x40000000,const int     GWL_STYLE = (-16),const int    SWP_NOMOVE = 0x02,    SWP_NOSIZE = 0x01,    SWP_NOZORDER = 0x04,    SWP_FRAMECHANGED = 0x20,[DllImport("user32.dll", SetLastError = true)]public static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent);[DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]public static extern uint GetWindowLong(IntPtr hwnd, int nIndex);[DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)]public static extern uint SetWindowLong(IntPtr hwnd, int nIndex, uint dwNewLong);var ptr = new IntPtr(HWND);var style = Win32API.GetWindowLong(ptr, Win32API.GWL_STYLE);if ((style & Win32API.WS_POPUP) != 0){    style &= ~Win32API.WS_POPUP;    style |= Win32API.WS_CHILD;    var rst0 = Win32API.SetWindowLong(ptr, Win32API.GWL_STYLE, style);    var rst1 = Win32API.SetWindowPos(ptr, 0, 0, 0, 0,0, Win32API.SWP_NOMOVE | Win32API.SWP_NOSIZE | Win32API.SWP_NOZORDER | Win32API.SWP_FRAMECHANGED);}var rst2 = Win32API.SetParent(ptr, _windowHandle);
原创粉丝点击