软工项目查许久资料才搞定,stackoverflow上的资料一直没说清楚花了不少时间 = =
借此水一篇博文,不过好像还需要实现一个让窗口不贴在桌面上的需求,但是这个把父窗口设置成Zero应该就行了
实现步骤
WPF中的应用场景:将窗口钉在桌面上,使用快捷键Win+D
显示桌面时不会让窗口隐藏
在窗口类中引入dll,调用系统api用于查找句柄、设置句柄等操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| [DllImport("user32.dll", SetLastError = true)] static extern UInt64 GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")] static extern int SetWindowLong(IntPtr hWnd, int nIndex, UInt64 dwNewLong);
[DllImport("user32.dll")] static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")] static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)] static extern IntPtr FindWindow(string lpWindowClass, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)] static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
|
然后通过窗口的特性来查找正确的桌面窗口
桌面窗口的类名为WorkerW
,但是根据这个类名会有重名的窗口,所以需要另外编写函数来进行查找
可以通过Microsoft Spy++来查看,正确的桌面窗口下至少有一个子窗口,其类名为SHELLDLL_DefView
查找正确桌面窗口句柄的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public static IntPtr SearchDesktopHandle() { IntPtr hRoot = GetDesktopWindow(); IntPtr hShellDll = IntPtr.Zero; IntPtr hDesktop = FindWindowEx(hRoot, IntPtr.Zero, "WorkerW", String.Empty); while (true) { hShellDll = FindWindowEx(hDesktop, IntPtr.Zero, "SHELLDLL_DefView", String.Empty); if (hShellDll != IntPtr.Zero) { return hDesktop; } hDesktop = FindWindowEx(hRoot, hDesktop, "WorkerW", String.Empty); }
return IntPtr.Zero; }
|
然后还需要把窗口添加一个WS_CHILD
的属性,否则调用SetParent
函数是没有任何用处的(注意:具有WS_POPUP
属性的窗口需要将其去掉,否则存在冲突)
1 2 3 4 5
| const int GWL_STYLE = (-16); const UInt64 WS_CHILD = 0x40000000; IntPtr hWnd = new WindowInteropHelper(this).Handle; UInt64 iWindowStyle = GetWindowLong(hWnd, GWL_STYLE); SetWindowLong(hWnd, GWL_STYLE, (iWindowStyle| WS_CHILD));
|
最后设置一下窗口的父窗口即可
1 2
| IntPtr desktopHandle = SearchDesktopHandle(); SetParent(hWnd, desktopHandle);
|
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public partial class MainWindow : Window{ [DllImport("user32.dll", SetLastError = true)] static extern UInt64 GetWindowLong(IntPtr hWnd, int nIndex); [DllImport("user32.dll")] static extern int SetWindowLong(IntPtr hWnd, int nIndex, UInt64 dwNewLong); [DllImport("user32.dll")] static extern IntPtr GetDesktopWindow(); [DllImport("user32.dll")] static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); [DllImport("user32.dll", SetLastError = true)] static extern IntPtr FindWindow(string lpWindowClass, string lpWindowName); [DllImport("user32.dll", SetLastError = true)] static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle); public static IntPtr SearchDesktopHandle() { IntPtr hRoot = GetDesktopWindow(); IntPtr hShellDll = IntPtr.Zero; IntPtr hDesktop = FindWindowEx(hRoot, IntPtr.Zero, "WorkerW", String.Empty); while (true) { hShellDll = FindWindowEx(hDesktop, IntPtr.Zero, "SHELLDLL_DefView", String.Empty); if (hShellDll != IntPtr.Zero) { return hDesktop; } hDesktop = FindWindowEx(hRoot, hDesktop, "WorkerW", String.Empty); } return IntPtr.Zero; } public MainWindow() { InitializeComponent(); } private void MainWindow_onLoaded(object sender, EventArgs e) { const int GWL_STYLE = (-16); const UInt64 WS_CHILD = 0x40000000; IntPtr hWnd = new WindowInteropHelper(this).Handle; UInt64 iWindowStyle = GetWindowLong(hWnd, GWL_STYLE); SetWindowLong(hWnd, GWL_STYLE, (iWindowStyle| WS_CHILD));
IntPtr desktopHandle = Utils.SearchDesktopHandle(); SetParent(hWnd, desktopHandle); } }
|
参考文章
SetWindowLongA function (winuser.h)
win32 修改窗口属性
GetWindowLongA function (winuser.h)
Window Styles