Phillip Trelford's Array

POKE 36879,255

Silverlight 5 Native Windows P/Invoke

Silverlight 5 brings native window and P/Invoke support for Silverlight desktop apps (elevated trust out-of-browser applications). The Silverlight Window class contains a subset of the properties and methods provided by in the equivalent WPF Window class. That subset of functionality may be enough for many users, and anything else can be implemented with a sprinkling of P/Invoke. Remember that .Net is mostly managed spackle over the Win32 API. With Silverlight 5 you can create your own managed spackle using P/Invoke.

Setting a Silverlight window’s transparency

WPF provides an AllowsTransparency property that you can set. Win32 provides a SetLayeredWindowAttributes function you can call:

public static void SetTransparency(IntPtr hwnd, byte alpha)
{
  // Note: the window must be in the hidden state for this to take effect
  SetWindowLong(hwnd, GWL_EXSTYLE, (int)(WS_EX_LAYERED + WS_EX_TRANSPARENT));
  SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA);
}

The SetLayeredAttributes function works on Layered Windows, so first we must set the window’s style to WS_EX_LAYERED using the Win32 SetWindowLong function.

[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hwnd, int nIndex);

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

Finally before we call our SetTransparency function we need to find the window’s handle:

public static IntPtr FindHwnd(Window window)
{
    var oldTitle = window.Title;
    var id = oldTitle + "(" + Guid.NewGuid().ToString() + ")";
    window.Title = id;
    var hwnd = FindWindowByCaption(IntPtr.Zero, id);
    window.Title = oldTitle;
    return hwnd;
}

The trick here is to temporarily give the window a unique title (using a GUID) and then find the window via it’s caption (title) using the Win32 FindWindow function.

[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpCaption);

Note: you can not click on the new transparent window which limits its usefulness to specific operations, for example a drag and drop cue window.

Removing a Silverlight window from the task bar

WPF provides a ShowInTaskBar property for this. Win32 provides an Extended Window Style WS_EX_NOACTIVATE which does the same:

public static void RemoveFromTaskBar(IntPtr hwnd)
{
    // Note: the window must be hidden for this to take effect
    SetWindowLong(hwnd, GWL_EXSTYLE, (int)WS_EX_NOACTIVATE);
}

Note: the window must have been shown then hidden before the method can work.

window.Show();
window.Hide();
Hwnd.RemoveFromTaskBar(hwnd);

Detecting when a windows is Activated/Deactivated

WPF provides Activated and Deactivated events. Win32 provides a WM_ACTIVATE message that you can listen in to:

[AllowReversePInvokeCalls]
private IntPtr WindowHook(int code, IntPtr wParam, IntPtr lParam)
{
    if (code == HC_ACTION)
    {
        var messageInfo = new CWPSTRUCT();
        Marshal.PtrToStructure(lParam, messageInfo);

        if (messageInfo.message == WM_ACTIVATE)
        {
            var hwnd = messageInfo.lparam;
            if ((int)messageInfo.wparam == WA_INACTIVE)
            {
                var e = WindowActivated;
                if (e != null)
                    e(this, new WindowActivatedEventArgs(hwnd));
            }
            else
            {
                var e = WindowDeactivated;
                if (e != null)
                    e(this, new WindowDeactivatedEventArgs(hwnd));
            }
        }

    }
    return CallNextHookEx(_hHook, code, wParam, lParam);
}

The method above is a hook for windows events. It triggers an event when a message signals that a window has become active or inactive. Calling SetWindowsHookEx starts it:

SetWindowsHookEx(WH_CALLWNDPROC, _callback, IntPtr.Zero, GetCurrentThreadId());

Summary

With a sprinkling of Managed spackle we’ve been able to extend the Silverlight 5 multi window feature. Silverlight 5’s P/Invoke feature provides a lot of customization potential.

The source code to this post is available on BitBucket:

Comments (1) -

  • John

    2/8/2013 5:55:56 AM |

    Great stuff. I was looking to achieve the glow/drop-shadow effect around windows that has become popular and you see with Visual Studio, for example.

    I can now make the whole window transparent - but do you know how to get rid of the white default background? Otherwise, I can't control where the transparency ought to go.

Pingbacks and trackbacks (1)+

Comments are closed