Search code examples
c#wpf.net-3.5aero-glass

Windows Aero Glass background is broken after hibernate. How can I solve this?


I am developing a program in C# .net 3.5 wpf. It has to work on windows xp, windows vista and windows 7. On the newer operation systems I wantet to create the background in Aero Glass. So this is only a special design. After hibernate, after suspending or after changing windows Desings to a basic design and back to aero all the added glass is displayed completely black.

I display Glass via the GlassHelper Class (can be found with Google).

Actually I see 3 ways to solve this problem. The first is, yea to solve it. But i read somwhere, that this is a bug in the Windows Managed Code so I have no option to sovle it. Correct me, if I am wrong.

So I had the idea to close the window everytime, it is minimized and to rebuild completely, when it s used next time.

That works quite well. After hibernate the window is still displayed black, but i do not have to quit the application, i can still minimize it and maximize again.

Now I see to ways:

1) I close the window everytime, the computer suspends, hibernates or changes the design. And I open it the window again, when it is save. But how can I handle this?

2) I accept, that the window will be displayed in black, until someone minimizes it. (Not my favourite) But then I get a new Problem: The Button in The Taskbar. (Not the Tray Icon). I need it to be displayed permanently. On winxp i need it to open the window, when minimized. And especially on win7 I need it because I want to use some of the new Advantages of the Superbar! (the preview by hoovering will not be the window, it will be a static picture.)

Thank you everyone, for helping me!


Solution

  • Ok, thank you everyone! But I think I found my own solution!

    I handle the Messages: WM_DWMCOMPOSITIONCHANGED (0x031E) & WM_THEMECHANGED (0x031A)

    and on catching one of those messages I simply assign the glass again or a new background depending on DwmIsCompositionEnabled().

    Actually I have something similar to the following:

    const int WM_THEMECHANGED = 0x031A;
    const int WM_DWMCOMPOSITIONCHANGED = 0x031E;
    
    private static void ApplyTheme(IntPtr hwnd)
    {
        if (DwmIsCompositionEnabled())
        {
            HwndSource.FromHwnd(hwnd).CompositionTarget.BackgroundColor = Colors.Transparent;
            MARGINS margins = new MARGINS(new Thickness(-1));
            DwmExtendFrameIntoClientArea(hwnd, ref margins);
        }
        else
        {
            HwndSource.FromHwnd(hwnd).CompositionTarget.BackgroundColor = SystemColors.ActiveCaptionBrush.Color;
        }
    }
    
    private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WM_THEMECHANGED)
        {
            ApplyTheme(hwnd);
        }
        if (msg == WM_DWMCOMPOSITIONCHANGED)
        {
            ApplyTheme(hwnd);
        }
        return IntPtr.Zero;
    }
    

    I get the hwnd.

    I hook it.

    HwndSource.FromHwnd(hwnd).AddHook(new HwndSourceHook(WndProc));
    

    I make the WPF Window Background transparent, because later, in the WndProc function I will only be able to access my hwnd Background (Win32).

    window.Background = Brushes.Transparent;
    

    And now I only have to assign the style for the first time:

    ApplyTheme(hwnd);
    

    Thats it! Works perfectly for me (Win 64 Home Premium) after I disable or enable aero, switch between different aero or non-aero styles or hibernate, so it is exactly, what I was looking for. Thank you, for your great ideas!