15
votes

I'm trying to create a "gadget" like application using WPF. The goal is to get the same behavior as a normal Windows 7 gadget:

  • No task-bar entry
  • Doesn't show up when you alt+tab windows
  • NOT always on top, applications can be on top
  • Visible while performing 'Aero Peek'
  • Visible while using 'Show desktop' / Windows+D

I've been able to accomplish the first four goals, but have been unable to find a solution to the fifth problem. The closest I've come is by using the utility class from How do you do AppBar docking (to screen edge, like WinAmp) in WPF?, but this turns the app into a "toolbar", thereby banishing applications from the part of the screen where my gadget GUI is placed.

I can see that similar questions has been asked previously on Stackoverflow, but those have died out before a solution was found. Posting anyway in the hope that there is now someone out there with the knowledge to solve this =)

4

4 Answers

1
votes

Try setting Topmost to true, and when your application loses focus you could set Opacity to 0.

I did this Xaml:

<Window x:Class="OpacTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Topmost="True" Background="Transparent" ShowInTaskbar="False" AllowsTransparency="True" WindowStyle="None" Width="400" Height="300">
    <Grid>
       <Border Background="Black" CornerRadius="5" />
    </Grid>
</Window>

I did this in C# for the Window:

protected override void OnActivated(EventArgs e)
{
    base.OnActivated(e);

    Opacity = 1;
}

protected override void OnDeactivated(EventArgs e)
{
    base.OnDeactivated(e);

    Opacity = 0;
}

This gets you part of the way there; you need a way to know if the desktop gets focus.

I bet you could do this by hooking into the WndProc event of the desktop window and looking for WM_ACTIVATE.

You could:

  • Call GetDesktopWindow to get the handle of the desktop window
  • Use a p/invoke call to set a callback for the WndProc
  • Handle WM_ACTIVATE or the appropriate windows message and set your Opacity back to 1
1
votes

You can implement an actual Windows Gadget using WPF by creating an XBAP. Just add a gadget.xml file and an .html file that contains only an IFRAME that loads the XBAP. That way your WPF application will actually be a gadget and will automatically follow all the rules.

Another option is to use Windows Sidebar Styler. This requires additional software to be installed alongside yours but also allows you to do things you can't do inside the XBAP sandbox without code signing certificates, user authorizaiton, etc.

A third option is to create a gadget that uses something recognizable in the HTML (such as a particular background color), then when your .exe starts up, scan for a hWnd under Explorer that has the attributes you are looking for, inject yourself into the Explorer.exe process, and set your window as a child of it.

A variation of the third option is to not inject into Explorer.exe but rather maintain your Z Index and location (using SetWindowPos) to track the Z Index and location of the hWnd you found.

So many choices...

1
votes

I'll leave this here for future reference.

In Windows 10, parent your gadget window to Desktop using p/invoke. Will work with peek, show desktop and Win + D

    [DllImport("user32.dll")]
    static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    public static void SetOnDesktop(Window window)
    {
        IntPtr hWnd = new WindowInteropHelper(window).Handle;
        IntPtr hWndProgMan = FindWindow("Progman", "Program Manager");
        SetParent(hWnd, hWndProgMan);

    }
0
votes

One solution to do achieve "gadget" like behavior, is to make your window a child of the desktop. In this way, your window is always visible on desktop even if you press Windows+D. You can see how it's done here: Window "on desktop".