Type.GetType(non corlib) - bug??

S

Saurabh

Hi All

I am trying to get a point from the LParam of the message by over-riding the
wndProc in my C# application. I think this is the only way to capture the
WM_NCLBUTTONUP message in .NET. Now my problem is, when I do something like,

Type t = Type.GetType("System.Object");
System.Type t1 = Type.GetType("System.Drawing.Point");
Point pt = (Point)m.GetLParam(t1);

When I execute the above code I get a valid type for t, but t1 comes as
<undefined value> which means i can't extract the point from the message m.
Is this a bug in .NET that you cannot get the type for the types which are
not in mscorlib.dll ??? thats just a guess 'coz I couldn't get the type
information for TextBox or Pens etc. Can anybody confirm this to be a bug?
Is there a fix?

The other question is, I can get a value in lparam property of the message,
Is there any way to translate this into point without using the GetLParam
method of the message?

TIA,

--Saurabh
 
J

Jon Skeet [C# MVP]

Saurabh said:
I am trying to get a point from the LParam of the message by over-riding the
wndProc in my C# application. I think this is the only way to capture the
WM_NCLBUTTONUP message in .NET. Now my problem is, when I do something like,

Type t = Type.GetType("System.Object");
System.Type t1 = Type.GetType("System.Drawing.Point");
Point pt = (Point)m.GetLParam(t1);

When I execute the above code I get a valid type for t, but t1 comes as
<undefined value> which means i can't extract the point from the message m.
Is this a bug in .NET that you cannot get the type for the types which are
not in mscorlib.dll ??? thats just a guess 'coz I couldn't get the type
information for TextBox or Pens etc. Can anybody confirm this to be a bug?
Is there a fix?

It's not a bug at all. Type.GetType(string) is behaving exactly as
documented:

<quote>
If typeName includes only the name of the Type, this method searches in
the calling object's assembly, then in the mscorlib.dll assembly. If
typeName is fully qualified with the partial or complete assembly name,
this method searches in the specified assembly.
</quote>

So, you either need to give the full assembly name which includes
System.Drawing.Point, or find/load the relevant Assembly and call
Assembly.GetType.

If you know the type in advance, however, it would be far better to use

Type t1 = typeof(System.Drawing.Point);
 
S

Saurabh

Thanks for the reply,
I did give the complete name as "System.Drawing.Point" or is this not
complete?

As you said, typeof(System.Drawing.Point) works... but I am still getting
the error in m.GetLParam( ) method. The error is

An unhandled exception of type 'System.NullReferenceException' occurred in
mscorlib.dll
Additional information: Object reference not set to an instance of an
object.

Though I think this might be something that I am doing wrong.

Thanks again for the response,

--Saurabh
 
J

Jon Skeet [C# MVP]

Saurabh said:
Thanks for the reply,
I did give the complete name as "System.Drawing.Point" or is this not
complete?

That's just the type name, not the assembly qulaified type name. The
runtime basically doesn't know which assembly to look in for the type
you're talking about.
As you said, typeof(System.Drawing.Point) works... but I am still getting
the error in m.GetLParam( ) method. The error is

An unhandled exception of type 'System.NullReferenceException' occurred in
mscorlib.dll
Additional information: Object reference not set to an instance of an
object.

Though I think this might be something that I am doing wrong.

Absolutely - but you haven't posted enough code to let us work out
what.
 
S

Saurabh

Well you are right, I haven't posted enough code... but simlpy thats all the
code which goes wrong. Maybe I failed to explain the problem properly.
Anyways here's the other relevant bits of the code. I am also doubtful about
the value of WM_NCLBUTTONUP 'coz my code seems to go there on double click.

This seems to work... sometimes. when I kept clicking in the NC area of my
form, after some time it threw that exception. In debug mode, It seems to
return the point sometimes and gives that error other times... Very
Unreliable. Can you suggest anything?

TIA again,

--Saurabh

[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);

[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hWnd);

[DllImport("user32.dll")]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

//Message constants as defined in winuser.h
public const int WM_NCPAINT = 0x0085;
public const int WM_NCLBUTTONDOWN = 0x00A1;
public const int WM_NCLBUTTONUP = 0x00A2;


protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case WM_NCPAINT:
{
//Draw additional button in titlebar
...

}
break;
case WM_NCLBUTTONUP:
{
//Check if our drawn button was hit
Type t = Type.GetType("System.Object");//works.. corlib??
System.Type t1 = Type.GetType("System.Drawing.Point"); //doesn't work non
corlib??
t1 = typeof(System.Drawing.Point); //thanks Jon skeet
Point pt = (Point)m.GetLParam(t1);
m.Result = IntPtr.Zero;
}
break;
case WM_NCLBUTTONDOWN:
{
Type t = Type.GetType("System.Object"); //works.. corlib??
System.Type t1 = Type.GetType("System.Drawing.Point");//doesn't work
t1 = typeof(System.Drawing.Point); //thanks Jon skeet
Point pt = (Point)m.GetLParam(t1);
m.Result = IntPtr.Zero;
}
break;
default :
break;
}
}
 
J

Jon Skeet [C# MVP]

Saurabh said:
Well you are right, I haven't posted enough code... but simlpy thats all the
code which goes wrong.

But chances are you've got other code which has set it up incorrectly.
Maybe I failed to explain the problem properly.
Anyways here's the other relevant bits of the code. I am also doubtful about
the value of WM_NCLBUTTONUP 'coz my code seems to go there on double click.

This seems to work... sometimes. when I kept clicking in the NC area of my
form, after some time it threw that exception. In debug mode, It seems to
return the point sometimes and gives that error other times... Very
Unreliable. Can you suggest anything?

Well, if you could post the full code, I could try to reproduce it...
without the full code, I can't.
 
S

Saurabh

Hi Jon,

Here's the short but complete code which does show the same behaviour. Keep
clicking in the title bar area of the form and it throws the exception.
------------------code-----------------
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;

namespace ShortButComplete
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);

[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hWnd);

[DllImport("user32.dll")]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

//Message constants
public const int WM_NCPAINT = 0x0085;
public const int WM_NCLBUTTONDOWN = 0x00A1;
public const int WM_NCLBUTTONUP = 0x00A2;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

protected override void WndProc(ref Message m)
{
base.WndProc (ref m);
switch (m.Msg)
{
case WM_NCPAINT:
{
IntPtr hDC = GetWindowDC(m.HWnd);
Graphics g = Graphics.FromHdc(hDC);
int CaptionHeight = Bounds.Height - ClientRectangle.Height;
Size CloseButtonSize = SystemInformation.CaptionButtonSize;
//position for buttons from left of close button
int X = Bounds.Width - 5 - CloseButtonSize.Width * 2;
int Y = 4;
ControlPaint.DrawButton(g, X, Y, 16, 16, ButtonState.Normal);
System.Drawing.Rectangle rect = new Rectangle(X + 2, Y + 2, 12, 12);
ControlPaint.DrawFocusRectangle(g, rect);
g.Dispose();
ReleaseDC(m.HWnd, hDC);
m.Result = IntPtr.Zero;
}
break;
case WM_NCLBUTTONUP:
{
Type t = Type.GetType("System.Object");
System.Type t1 = Type.GetType("System.Drawing.Point");
t1 = typeof(System.Drawing.Point);
String str = t1.AssemblyQualifiedName.ToString();
Type t2 = Type.GetType(str);
Object o = m.GetLParam(t2);
Point pt = (Point)o;
m.Result = IntPtr.Zero;
}
break;
default :
break;
}
}


#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(322, 295);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Form1";
this.Text = "Form1";

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}
}
---------------end of code-------------
 
J

Jon Skeet [C# MVP]

Saurabh said:
Here's the short but complete code which does show the same behaviour. Keep
clicking in the title bar area of the form and it throws the exception.

Hmm... right, I can reproduce it now. I can't instantly see why it's
happening, but I'll look into it further. It *always* happens in the
test case though - the code only gets triggered by a double click (as
you said before) but never seems to get past the call to GetLParam. How
sure are you that the POINTS Win32 structure can be marshalled to a
Point .NET structure?

I'll have a look at why you're getting the message you are - that looks
odd, too.

I spotted this in your code by the way:
Type t = Type.GetType("System.Object");
System.Type t1 = Type.GetType("System.Drawing.Point");
t1 = typeof(System.Drawing.Point);
String str = t1.AssemblyQualifiedName.ToString();
Type t2 = Type.GetType(str);

Why are you getting the type, then getting its name, then getting the
type again? The whole of the above can be reduced to:

Type t = typeof(object);
// t1 isn't used any more
Type t2 = typeof(System.Drawing.Point);

That isn't the cause of the problem, but it's worth clearing up.
 
S

Saurabh

Oops sorry!!

I just went on adding lines in the code when u said about the complete
assembly name etc. to make sure that it works... its nothing to do with the
actual logic.

Do you mean that you cannot even execute the code once? I did get it to
correctly execute and go past the GetLParam and got the valid values in
Point. For example If I insert a break point in the code and double click on
the button I seem to go past that code and get a point (X = 0, Y = 0 which
is a different worry altogether) and in the title bar also I get point
object with some other values.....

I am now forming the opinion as to I need to handle some other messages as
well and handle them.

Aaah thinking about it, The value mighe be garbage but if for some reason it
can be casted to Point the code works and otherwise not.... I will try
something else....

Thanks for your support!!

--Saurabh
 
S

Saurabh

Thanks Eric.
Thats excellent.... It works, I am not sure I need the PointToclient( )
call, but I was basically after the conversion of lParam which is excellent
as you have specified.

Thanks once again,

--Saurabh
 
C

Claes Bergefall

There's no need to use those LoWord and HiWord functions
The Point structure in .NET has a constructor that takes an int
exactly as it is layed out in the various mouse messages

Point pt = new Point(m.LParam.ToInt32);

/claes
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top