简体   繁体   中英

“pin to desktop” in Win 7, XP compatible

How could I achieve "pin to desktop" effect (ie immune against "Show Desktop" command) in Win 7, using FindWindow + SetParent approach, or any other approach that would work in XP as well ? I know I could create a gadget, but I'd like to have backwards compatibility with XP, where I have this code doing it fine:

IntPtr hWnd = FindWindow(null, "Untitled - Notepad");
IntPtr hDesktop = FindWindow("ProgMan", "Program Manager");
SetParent(hWnd, hDesktop);

in my WPF app, I was able to solve it using a timer, it's working both in XP and Win 7.

public MainWindow()
{
    InitializeComponent();

    // have some timer to fire in every 1 second
    DispatcherTimer detectShowDesktopTimer = new DispatcherTimer();
    detectShowDesktopTimer.Tick += new EventHandler(detectShowDesktopTimer_Tick);
    detectShowDesktopTimer.Interval = new TimeSpan(0, 0, 1);
    detectShowDesktopTimer.Start();
}

#region support immunizing against "Show Desktop"
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);

private string GetWindowText(IntPtr handle)
{
    int chars = 256;
    StringBuilder buff = new StringBuilder(chars);
    if (GetWindowText(handle, buff, chars) > 0)
        return buff.ToString();
    else
        return string.Empty;
}
#endregion

private void detectShowDesktopTimer_Tick(object sender, EventArgs e)
{
    IntPtr fore = GetForegroundWindow();
    if (string.IsNullOrWhiteSpace(GetWindowText(fore)))
        ShowDesktopDetected();
}

private void ShowDesktopDetected()
{
    WindowInteropHelper wndHelper = new WindowInteropHelper(this);
    SetForegroundWindow(wndHelper.Handle);
}

While working on a calendar "glued to the desktop", I ran into the same problem. Here is my solution:

/************ win32 interop stuff ****************/


[DllImport( "user32.dll", SetLastError = true )]
static extern int SetWindowLong( IntPtr hWnd, int nIndex, IntPtr dwNewLong );

[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 );


const int GWL_HWNDPARENT = -8;


/************* in Form_Load or equivalent ***************/


IntPtr hprog = FindWindowEx(
    FindWindowEx(
        FindWindow( "Progman", "Program Manager" ),
        IntPtr.Zero, "SHELLDLL_DefView", ""
    ),
    IntPtr.Zero, "SysListView32", "FolderView"
);

SetWindowLong( this.Handle, GWL_HWNDPARENT, hprog );

The tricky part was to set the form's owner (SetWindowLong + GWL_HWNDPARENT) instead of the form's parent (SetParent). This fixed the form not being rendered on an aero desktop.

The answers to this question should help:

If not, you could implement it as an active desktop application in XP. Or if it's a simple view-only application, you could actually draw on the desktop wallpaper.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM