Friday, February 27, 2009

What's the scope of window handles?

Someone stated (though I've yet to find any supporting MSDN documents) that window handles are global to all processes belonging to the same window station. Yet, if you somehow obtain a handle to a window belonging to another desktop, and try to send messages to it, SendMessage may fail with ERROR_INVALID_WINDOW_HANDLE. Why?

If window handles are truly global, then, say, thread 'a' on desktop 'A' should be able to use handles from thread 'b' on desktop 'B', assuming that both desktops belong to the same window station, right? It seems that some magic needs to happen for the handle table to be visible to other desktops, that is, thread 'a' needs to obtain a handle to desktop 'B' with read access.

It appears logical, but needs to be clearly documented!

Tuesday, December 30, 2008

Where is the caret?

Carefully minded will spot at least one subtle difference between the Visual Studio editor, and the RichEdit control: the caret in selection. Why oh why I can get this cute blinking cursor when I select some text in Visual Studio, but not in WordPad or in RichTextBox?

Maybe it's hidden for some bizarre reasons, I'll just call ShowCaret to bring it back. Argh, doesn't work? OK, may be HideCaret is called multiple times, so I'll just call ShowCaret a zillion times to see what gives. What? The caret is actually destroyed, and I have to call CreateCaret?

How am I supposed to know the height of the caret? It's not exactly Font.Height, and I can't always get the position of two lines and take the difference.

Text Object Model (TOM) comes into rescue. It's implemented by RichEdit (not Edit, so no hope there, yet). Get an IRichEditOle with EM_GETOLEINTERFACE, then an ITextDocument, then an ITextRange from ITextDocument::Range, and finally the coordinates from ITextRange::GetPoint.

I'll leave it as an exercise to declare the TOM interfaces for .net. Yea this whole thing is purely artistic...

Friday, June 27, 2008

MSDN Documentation. Follow or Not Follow?

When reading MSDN, often time there are sentences like "do not do XXX" or "you have to do YYY" without further explanation. This time it is on the OFNHookProc page:

Do not call the EndDialog function from the hook procedure.


It happened that I also came across the HookProc implementation in FileDialog, using the .Net Reflector:

[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected override IntPtr HookProc(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam) {
    // ......
    } catch {
        if (this.dialogHWnd != IntPtr.Zero) {
            UnsafeNativeMethods.EndDialog(new HandleRef(this, this.dialogHWnd), IntPtr.Zero);
        }
        throw;
    }
    // ......
}


May be the .net team know win32 in and out that outsider rules don't apply to them; or may be sometimes it is acceptable to ignore MSDN.

Wednesday, April 30, 2008

How to detect audio in DVR-MS files?

Just yesterday I was working on the audio detection in dvr-ms files in one software. Seeing it as a proprietary format, I didn't expect much information on dvr-ms from the ASF specification or from MSDN(link). Some open source projects come to rescue, and the key GUID has been discovered.

Here's how I'm doing it:

When parsing ASF_Binary_Media, if the Major Media Type is 31178c9d-03e1-4528-b5823df9db22f503, and the Format Type is 05589f81-c356-11ce-bf0100aa0055595a or c4c4c4d1-0049-4e2b-98fb9537f6ce516d, then I can expect the Format Data to be WAVEFORMATEX(link), padded up to Format Data Size.

Tuesday, April 29, 2008

Why Visual Studio Limits Me to a Specific C Runtime?

A while ago I wrote a Windows application with Visual Studio 2008. Everything went fine when tested on the development platform (Server 2003), but when I deployed it on Windows XP, the system complained that the application needed to be reinstalled.

What?

I scratched my head. My application was simple enough that it had only one executable, required no fancy installation, and I double checked that it didn't depend on anything specific to Server 2003.

In fact it did, sort of. It was linked to a version of VC runtime that doesn't ship with Windows XP, according to Dependency Walker.

How did that happen? Turned out that Visual Studio 2008 comes with this latest and greatest msvcr90.dll, and my application happened to use some C library functions. With the "right" compiler settings, msvcrt.lib (version 9) was linked in, and so I had no choice but needed this CRT to run a simple Windows application on XP.

What a great idea. An additional dll that's several times bigger than my application.

Or did I have a choice?

I could statically link the new CRT, thus only need to ship one executable file. Nah, that doesn't solve the size problem.

I could copy the old msvcrt.lib to tell VS that the application needs the old msvcrt.dll, which ships with XP, and thus eliminate the need of msvcr90.dll.

Or so I thought. Or so depends.exe said. What happened was, to use themed common controls, I told VS to include the proper manifest; and to avoid distributing yet another file, I told VS to embed (hide) the manifest in the executable. Little did I know that this manifest also included a dependency on Microsoft.VC90.CRT...

Now I could use Resource Hacker to edit that out. It would have been easier if VS allowed me to choose the version of CRT to begin with.

Of course, in the end, I started from this article and dropped the C runtime functions altogether.

Thursday, February 7, 2008

How to modify PropertyGrid's internal controls?

PropertyGrid is a wonderful control. But this post is not to praise it; more to solve a practical problem.

PropertyGrid has an internal ToolStrip, among other controls. This ToolStrip provides sorting commands, but sometimes it's necessary to add other commands to it, like importing and exporting reflected data, settings, etc.

This ToolStrip is not publicly exposed, so one alternate solution is to set ToolbarVisible = false and provide a custom ToolStrip.

But wouldn't it be easier if the internal ToolStrip can be modified at will?

That can't be too hard. The following code should do:

public partial class MyPropertyGrid : System.Windows.Forms.PropertyGrid {
    public ToolStrip InternalToolStrip {
        get {
            foreach (Control ctrl in base.Controls) {
                if (ctrl is ToolStrip) {
                    return ctrl as ToolStrip;
                }
            }
            return null;
        }
    }
}


Now place MyPropertyGrid on a form, and check the Properties Window. There! Change InternalToolStrip any way seems fit.

Of course, this world ain't perfect. It's less desirable to edit this ToolStrip only from the Properties Window; plus, there's a bigger problem at runtime. They will be covered next.

Sunday, November 11, 2007

RichTextBox is not a simple RichEdit wrapper?

There are several annoyances with the Rich Edit control. For example, using EM_STREAMIN / EM_STREAMOUT with EditStreamCallback will clear its undo and redo queues. Why would this caused by simply reading the stream is beyond me.

The .net RichTextBox inherits this problem, which means accessing its Text, Rtf, and Lines properties will clear the queues. What's more, calling its GetCharIndexFromPosition and GetPositionFromCharIndex functions will also clear the queues. Why is that? Don't GetCharIndexFromPosition and GetPositionFromCharIndex just wrap EM_CHARFROMPOS and EM_POSFROMCHAR?

Workarounds?
  • Replace functions GetCharIndexFromPosition / GetPositionFromCharIndex with EM_CHARFROMPOS / EM_POSFROMCHAR
  • Replace property Text with EM_GETTEXTEX / RichTextBox.SelectAll / SelectedText
  • Replace property Lines with EM_GETTEXTEX / String.Split / Join
  • Replace property Rtf with... no idea.