Wednesday, July 07, 2004

Another bug, another workaround...

I was using Genghis to create a standard Find and Replace dialog, when I hit another bug in the .NET framework (this is getting boring...):
The System.Windows.Forms.NativeWindow class has a problem on the ReleaseHandle method: I don't know (don't care) why, when you subclass a window using the NativeWindow class, your new WndProc will still be called, even after the ReleaseHandle. On the Genghis FindReplaceDialog class, this bug appears when you invoke the dialog twice: your WndProc will be called for a while, and then, BAM! A call to a collected delegate will happen. I googled a lot and found nothing, so I coded the following workaround. When you need to subclass a window, just derive from my class instead of deriving from System.Windows.Forms.NativeWindow class and you won't need to change a single line of code!
class NativeWindow
{
private IntPtr handle;
private WndProcDelegate wndProcDelegate; // Prevents the delegate being collected
private IntPtr oldWndFunc;
private delegate IntPtr WndProcDelegate(IntPtr hwnd, int Msg, IntPtr wParam, IntPtr lParam);

private const int GWL_WNDPROC = -4;

[DllImport("User32.dll")]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, WndProcDelegate wndProcDelegate);
[DllImport("User32.dll")]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr wndFunc);

[DllImport("User32.dll")]
private static extern IntPtr CallWindowProc(IntPtr prevWndFunc, IntPtr hWnd, int iMsg, IntPtr wParam, IntPtr lParam);

public NativeWindow()
{
wndProcDelegate = new WndProcDelegate(this.WndProc);
}

public void AssignHandle(IntPtr hWnd)
{
handle = hWnd;
oldWndFunc = SetWindowLong(hWnd, GWL_WNDPROC, wndProcDelegate);
}

public void ReleaseHandle()
{
SetWindowLong(handle, GWL_WNDPROC, oldWndFunc);
handle = IntPtr.Zero;
oldWndFunc = IntPtr.Zero;
}

protected virtual void WndProc(ref Message msg)
{
DefWndProc(ref msg);
}

public void DefWndProc(ref Message m)
{
m.Result = CallWindowProc(oldWndFunc, m.HWnd, m.Msg, m.WParam, m.LParam);
}

private IntPtr WndProc(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam)
{
Message msg = Message.Create(hWnd, Msg, wParam, lParam);
WndProc(ref msg);
return msg.Result;
}
}

Comments:
thank's you are the man

Offir
 
Hello Daniel,

I need override WndProc for TextBox controls which i have placed on forms [For Win CE using C#]. If i use delegate method it is giving exception of "Callback to garbage collected delegate".

Is there any solution for this.

Thanks in advance
 
Post a Comment

<< Home

This page is powered by Blogger. Isn't yours?