outcoldman
outcoldman Denis Gladkikh

Windows 7 & DWN: знаете ли вы, что не все окна должны подчиняться Flip3D и Aero Peek

.NET, C#, WPF, Vista, Windows 7, and Aero

Вы, наверняка, знаете, что в Vista и Windows 7 существует функция Flip3D, а в Windows 7 еще и Aero Peek.

Aero Peek Flip3D

Но вы, наверняка, не знаете, что можно заставить ваше окно (приложение) не подчиняться правилам для всех окон в данных возможностях Windows. Для этого следует изучить Desktop Window Manager API.

Итак, с чего начать? Как всегда, если мы пишем приложение на .net (WinForms или WPF), нам нужно проимпортировать необходимые методы. Стоит заметить, что в случае WinForms получить HWND окна очень просто, для этого есть свойство Form::Handle, в случае же WPF можно воспользоваться классом WindowInteropHelper, так чтобы получить HWND главного окна можно написать так:

IntPtr hwnd = new WindowInteropHelper(Application.Current.MainWindow).Handle;

Вернемся теперь к необходимым функциям. Первая функция на которую стоит обратить внимание – это DwmIsCompositionEnabled, она нам позволяет определить включен ли Aero Glass на компьютере:

public partial class FormSample : Form
{
    [DllImport("dwmapi.dll", PreserveSig = false)]
    public static extern bool DwmIsCompositionEnabled();
 
    public FormSample()
    {
        InitializeComponent();
 
        if (Environment.OSVersion.Version.Major < 6)
        {
            // Dwm не работает, старая версия Windows
        }
        else if (!DwmIsCompositionEnabled())
        {
            // Aero Glass и Aero 3D отключены (не поддерживаются) 
        }
        else
        {
            // Aero Glass и Aero 3D работают
        }
    }
}

Отлично, теперь мы знаем когда можно “играться” с Dwm, следующая функция, которая поможет нам работать с Dwn – это DwmSetWindowAttribute. Это уже основная функция, при помощи которой мы можем управлять нашим окном и говорить системе как его следует отображать.

Например, действие первое. Задача, мы хотим сделать такое приложение, которое отображается даже тогда, когда пользователь включает режим Aero Peek (действие, похожее на гаджет). Представьте на вашем мониторе куча запущенных окон, вам лень искать необходимое окно при помощи WinKey+Tab, а хочется увидеть нужные окна при помощи WinKey+Space – это может быть и обычный мессенджер, и какой-то ваш профайлер, при помощи которого вы следите за работой чего либо, ну и многое другое. Так, например, вот в этой статье “Joel 'Jaykul' Bennett - Fun with PInvoke and Aero Peek“ описывается как можно сделать это с популярным мессенджером Miranda (с этой статьи меня и заинтересовал Dwn и какие возможности он еще предоставляет). Правда в данной статье используются флаги DwmNCRenderingPolicy, которые на самом деле пригодны для установления значений при использовании флага DWMWA_NCRENDERING_POLICY, а не DWMWA_EXCLUDED_FROM_PEEK. Для обычной формы это можно сделать так:

public partial class FormSample : Form
{
    [Flags]
    public enum DwmWindowAttribute
    {
        ExcludedFromPeek = 12
    }
 
    [DllImport("dwmapi.dll", PreserveSig = false)]
    public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
 
    public static void RemoveFromAeroPeek(IntPtr hwnd)
    {
        int attrValue = 1; // TRUE
        DwmSetWindowAttribute(hwnd, (int)DwmWindowAttribute.ExcludedFromPeek, ref attrValue, sizeof(int));
    }
 
    public FormSample()
    {
        InitializeComponent();
        // Делаем видимым при Aero Peek
        RemoveFromAeroPeek(Handle);
    }
}

Результат будет таким (это чтобы было более понятно о чем я вообще пишу):

Remove Aero Peek Result

Так же можно заставить свое окно не подчиняться правилам Aero 3D (это когда используем WinKey+Tab для переключения между окнами). Для этого нужно рассмотреть атрибут DWMWA_FLIP3D_POLICY, для него можно установить значения “Обычное поведение”, “Показывать поверх 3D”, “Показывать за 3D”, правда у меня работало либо “обычное поведение”, либо “показывать за 3D”, поверх не получилось сделать.

{
    [Flags]
    public enum DwmWindowAttribute
    {
        Flip3DPolicy = 8
    }
 
    // Flip 3D policies
    public enum Flip3DPolicy
    {
        Default = 0,
        ExcludeBelow,
        ExcludeAbove
    }
 
    [DllImport("dwmapi.dll", PreserveSig = false)]
    public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
 
    public static void SetFlip3DPolicy(IntPtr hwnd)
    {
        int attrValue = (int)Flip3DPolicy.ExcludeBelow; 
        DwmSetWindowAttribute(hwnd, (int)DwmWindowAttribute.Flip3DPolicy, ref attrValue, sizeof(int));
    }
 
    public FormSample()
    {
        InitializeComponent();
        SetFlip3DPolicy(Handle);
    }
}

Результат следующий:

Set 3DFlip Policy Result

Как это можно использовать – уже сложнее представить. Ну…, мое дело рассказать :) Удачи!

Have feedback or questions? Looking for consultation?

My expertise: MongoDB, ElasticSearch, Splunk, and other databases. Docker, Kubernetes. Logging, Metrics. Performance, memory leaks.

Send me an email to public@denis.gladkikh.email.

The content on this site represents my own personal opinions and thoughts at the time of posting.

Content licensed under the Creative Commons CC BY 4.0.