Friday, November 18, 2005

Z-order, shmee-order

Ever wanted to have a window that refused to come to the top, staying as close to the bottom of the z-order as possible? I know I hadn't. But, someone at work was asking how it could be done, so I tried it out. It's actually not too hard; it all works through Win32 APIs, so it would be a bit easier through C/C++, but it's not too bad in .NET. Here's all the code you need to add to a form:
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
If m.Msg = WM_WINDOWPOSCHANGING Then
Dim PositionInfo As WINDOWPOS = m.GetLParam(GetType(WINDOWPOS))
PositionInfo.hwndInsertAfter = HWND_BOTTOM
Marshal.StructureToPtr(PositionInfo, m.LParam, False)
m.Result = 0
End If
End Sub
I've omitted the Imports and the declarations of those Windows constants for brevity. If any of you cares how it works, here goes: Windows sends the message WM_WINDOWPOSCHANGING to every top-level window (i.e. a "regular window," not a button) when its position changes. By responding to this message, an application can do all sorts of wacky stuff, including retaining the window's aspect ration like QuickTime, or docking to other windows like Winamp, or mucking around with the z-order like me. In the LParam (parameter #2) of that function callback is a pointer to a WINDOWPOS structure. That structure contains an HWND (window handle) to the window that the current window should be inserted after. But, instead of passing in a real window handle, you can also pass in predefined special codes, such as HWND_BOTTOM, which means to insert it into the z-order after everything. You then return 0 to indicate that you handled the message.

Windows Forms (.NET) makes this a little harder because the WINDOWPOS structure accessible from code can move around or change at any time, so it has to be copied from the pointer from Windows, then modified, and then copied back onto the pointed memory address. I believe you can do this more efficiently (without having to copy stuff) from C# using an unsafe{} block and pointers, but it was just an exercise.

This post has to win some kind of award for most worthless ever.

1 comment:

Derrick Stolee said...

not worthless, actually.

I now know that you can go back and do all of that low-level GUI stuff that MFC and the Windows 32-bit API let you do. I don't think I'll use it in the near future, but maybe... you never know.