デジタルサイネージなどでのアプリケーションでは、タスクバーのように画面の端に固定して他のアプリケーションが被さらないようにデスクトップ領域を変更したいときがあります。
実際は、タスクバーを消したりしてあたかもタスクバーのように見せたりすることがあります。
今回は、アプリケーションデスクトップツールバーについてのサンプルを載せておきます。
今回のサンプルの動作
左図は、通常のWindows10のデスクトップです。下にタスクバーのStartボタンが見えます。
真ん中の図は、今回作成したなんちゃってタスクバーのテスト版です。ここでは、タスクバーに被らないように左端にピンクのバーを作成しています。デスクトップのショートカットがずれているのがわかると思います。なんちゃってタスクバーをフルサイズにしているので、Startボタンが隠れてしまいました。
右図は、ブラウザを最大表示したものです。なんちゃってバーに被っていないことがわかると思います。タスクバーを触るとタスクバーがTOPになってしまいます。実際は、タスクバーを隠すか、削除してしまえば問題ないと思います。
アプリケーションデスクトップツールバーは、Win32APIを呼び出して使うことになります。アプリケーションデスクトップツールバーの登録を行うには SHAppBarMessage で設定します。今回は、左端に固定するためにABE_LEFTを指定しています。
サンプルプログラム
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
namespace TShell
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
const int SWP_SHOWWINDOW = 0x0040;
const int HWND_TOPMOST = -1;
public const int ABE_BOTTOM = 3;
public const int ABE_LEFT = 0;
public const int ABE_RIGHT = 2;
public const int ABE_TOP = 1;
public const int ABM_QUERYPOS = 2;
public const int ABM_SETPOS = 3;
public const long WS_EX_APPWINDOW = 0x00040000L;
public const long WS_EX_TOOLWINDOW = 0x00000080L;
public const int GWL_EXSTYLE = -20; // 拡張スタイル
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[StructLayout(LayoutKind.Sequential)]
private struct APPBARDATA
{
public int cbSize;
public IntPtr hWnd;
public int uCallbackMessage;
public int uEdge;
public RECT rc;
public IntPtr lParam;
}
private enum ABMsg : int
{
ABM_NEW = 0,
ABM_REMOVE,
ABM_QUERYPOS,
ABM_SETPOS,
ABM_GETSTATE,
ABM_GETTASKBARPOS,
ABM_ACTIVATE,
ABM_GETAUTOHIDEBAR,
ABM_SETAUTOHIDEBAR,
ABM_WINDOWPOSCHANGED,
ABM_SETSTATE
}
[DllImport("SHELL32", CallingConvention = CallingConvention.StdCall)]
private static extern uint SHAppBarMessage(int dwMessage, ref APPBARDATA pData);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy, int uFlags);
[DllImport("User32.dll")]
private static extern long GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern UInt32 SetWindowLong(IntPtr hWnd, int index, UInt32 unValue);
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
int height = (int)SystemParameters.PrimaryScreenHeight;
int width = (int)SystemParameters.PrimaryScreenWidth;
IntPtr handle = new WindowInteropHelper(this).Handle; // 自分のウィンドウハンドルを取得する
// 登録領域から外されないように属性を変更する
long style = GetWindowLong(handle, GWL_EXSTYLE);
style ^= WS_EX_APPWINDOW;
style |= WS_EX_TOOLWINDOW;
SetWindowLong(handle, GWL_EXSTYLE, (uint)style);
SetWindowPos(handle, HWND_TOPMOST, 0, 0, 40, height, SWP_SHOWWINDOW);
// AppBarの登録
APPBARDATA barData = new APPBARDATA();
barData.cbSize = Marshal.SizeOf(barData);
barData.hWnd = handle;
SHAppBarMessage((int)ABMsg.ABM_NEW, ref barData);
barData.uEdge = ABE_LEFT; // 左端に登録する
barData.rc.top = 0;
barData.rc.left = 0;
barData.rc.right = 40; // なんちゃってタスクバーの横幅
barData.rc.bottom = (int)SystemParameters.PrimaryScreenHeight;
GetWindowRect(handle, out barData.rc);
SHAppBarMessage(ABM_QUERYPOS, ref barData);
SHAppBarMessage(ABM_SETPOS, ref barData);
}
private void Window_Closed(object sender, EventArgs e)
{
// AppBarの登録解除
APPBARDATA barData = new APPBARDATA();
barData.cbSize = Marshal.SizeOf(barData);
barData.hWnd = new WindowInteropHelper(this).Handle;
SHAppBarMessage((int)ABMsg.ABM_REMOVE, ref barData);
}
}
}
参考
https://learn.microsoft.com/ja-jp/windows/win32/shell/application-desktop-toolbars