You are not logged in.

#1 21 Aug 2006 5:57 am

Jocker
Member
Registered: Aug 2006
Posts: 6
Website

An IPAddress Control (the Win32 SysIPAddress32 control in C#)

Hi Steve,
I've tried your IPAddress control and found it throws an exception at load time.

I'm using C# 2.0 on WinXP: I've put your source code unaltered in a class, compiled and put it in a winform. Here is the whole solution.
Both in the designer and when executing, I get an AccessViolationException in the WndProc method when the message is "msg=0xe (WM_GETTEXTLENGTH) hwnd=0x31486 wparam=0x0 lparam=0x0 result=0x0".
If I catch and ignore this exception (or if I filter the WM_GETTEXTLENGTH before base.WndProc(ref m); is called), the control seems to work as expected.

Can you replicate it and/or suggest a way to solve it? Is ignoring the WM_GETTEXTLENGTH message a safe workaround?
Thanks

Offline

 

#2 21 Aug 2006 7:11 am

MadHatter
Administrator
From: Dallas TX
Registered: Jun 2006
Posts: 529
Website

Re: An IPAddress Control (the Win32 SysIPAddress32 control in C#)

whats sending the wm_gettextlength message (are you sending it to find the length of the octet or something)?

If I send it directly I dont get an exception (I'm running xp x64 here, I'll have to recheck it when I get to work w/ a 32 bit machine).

the control should actually derive from System.Control (which is what my "nicer version" that got lost derived from) so it should be safe to ignore.

Offline

 

#3 21 Aug 2006 8:54 am

MadHatter
Administrator
From: Dallas TX
Registered: Jun 2006
Posts: 529
Website

Re: An IPAddress Control (the Win32 SysIPAddress32 control in C#)

I tried it here at work on a 32bit machine too (xp as well) and cant reproduce it.  here is what I'm testing with:

Code:

public partial class Form1 : Form {
    const int WM_GETTEXTLENGTH = 0x0E;
    public Form1() {
        InitializeComponent();
    }
    private void button1_Click(object sender, EventArgs e) {
        IntPtr result = 
            SendMessage(ipAddressControl1.Handle, 
                        WM_GETTEXTLENGTH, 
                        IntPtr.Zero, 
                        IntPtr.Zero);
        MessageBox.Show(result.ToInt32().ToString());
    }
    [DllImport("user32")]
    static extern IntPtr SendMessage(IntPtr hwnd, 
                                     int msg, 
                                     IntPtr wParam, 
                                     IntPtr lParam); 
}

and its comming back w/ the right size & no error.


would you mind posting a code sample?

Offline

 

#4 22 Aug 2006 1:04 am

Jocker
Member
Registered: Aug 2006
Posts: 6
Website

Re: An IPAddress Control (the Win32 SysIPAddress32 control in C#)

Hi
thank you for the quick response

MadHatter :

whats sending the wm_gettextlength message (are you sending it to find the length of the octet or something)?

I'm not sending it. It comes automatically

MadHatter :

would you mind posting a code sample?

I already did in the first post.. maybe the link color is too similar to the other text color to notice smile
http://www.jockersoft.com/temp/iptextbox.rar

MadHatter :

the control should actually derive from System.Control (which is what my "nicer version" that got lost derived from) so it should be safe to ignore.

If derived from System.Windows.Forms.Control the exception disappears, but the control renders in this way:
http://img244.imageshack.us/img244/6820/controlgn1.png

Jocker

Offline

 

#5 22 Aug 2006 6:41 am

MadHatter
Administrator
From: Dallas TX
Registered: Jun 2006
Posts: 529
Website

Re: An IPAddress Control (the Win32 SysIPAddress32 control in C#)

hrm... yea I missed the sample.  I run it here at home just fine, I'll see at work but its exactly like my other tests so...

deriving it from textbox draws the "textbox" like box, as well as handles some of the keystrokes that arent implemented in the standard control.


can you change the

Code:

MessageBox.Show(ex.GetType() + ": " + ex.Message + Environment.NewLine + m);

to

Code:

System.Diagnostics.Debug.WriteLine(ex.ToString());

and copy the stack trace out of the output window in visual studio and paste it here?

Offline

 

#6 22 Aug 2006 9:08 am

Jocker
Member
Registered: Aug 2006
Posts: 6
Website

Re: An IPAddress Control (the Win32 SysIPAddress32 control in C#)

here it is

Code:

System.AccessViolationException: Attempted to read or write protected
memory. This is often an indication that other memory is corrupt.
   in System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   in System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
   in System.Windows.Forms.Control.DefWndProc(Message& m)
   in System.Windows.Forms.Control.WndProc(Message& m)
   in System.Windows.Forms.TextBoxBase.WndProc(Message& m)
   in System.Windows.Forms.TextBox.WndProc(Message& m)
   in NullFX.Controls.IPAddressControl.WndProc(Message& m) in C:\Documents and Settings\Jocker\Desktop\iptxt\iptextbox\IPAddressControl.cs:riga 168

the loaded assemblies are:

Code:

'tester.vshost.exe' (managed): Loaded 'C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'tester.vshost.exe' (managed): Loaded 'C:\WINDOWS\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Utilities\8.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Utilities.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'tester.vshost.exe' (managed): Loaded 'C:\WINDOWS\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a5c561934e089\System.Windows.Forms.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'tester.vshost.exe' (managed): Loaded 'C:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'tester.vshost.exe' (managed): Loaded 'C:\WINDOWS\assembly\GAC_MSIL\System.Drawing\2.0.0.0__b03f5f7f11d50a3a\System.Drawing.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'tester.vshost.exe' (managed): Loaded 'C:\WINDOWS\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Utilities.Sync\8.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Utilities.Sync.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'tester.vshost.exe' (managed): Loaded 'C:\WINDOWS\assembly\GAC_MSIL\mscorlib.resources\2.0.0.0_it_b77a5c561934e089\mscorlib.resources.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'tester.vshost.exe' (managed): Loaded 'C:\Documents and Settings\Jocker\Desktop\iptxt\tester\bin\Debug\tester.vshost.exe', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'tester.vshost.exe' (managed): Loaded 'C:\WINDOWS\assembly\GAC_32\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'tester.vshost.exe' (managed): Loaded 'C:\WINDOWS\assembly\GAC_MSIL\System.Deployment\2.0.0.0__b03f5f7f11d50a3a\System.Deployment.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'tester.vshost.exe' (managed): Loaded 'C:\WINDOWS\assembly\GAC_MSIL\System.Xml\2.0.0.0__b77a5c561934e089\System.Xml.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
The thread 0x4d0 exited with code 0 (0x0).
'tester.vshost.exe' (managed): Loaded 'C:\Documents and Settings\Jocker\Desktop\iptxt\tester\bin\Debug\tester.exe', Symbols loaded.
'tester.vshost.exe' (managed): Loaded 'C:\Documents and Settings\Jocker\Desktop\iptxt\tester\bin\Debug\iptextbox.dll', Symbols loaded.

everything seems regular hmm

Offline

 

#7 22 Aug 2006 10:33 am

MadHatter
Administrator
From: Dallas TX
Registered: Jun 2006
Posts: 529
Website

Re: An IPAddress Control (the Win32 SysIPAddress32 control in C#)

one more request.  can you replace the WndProc method w/ this one and post the output again?

it looks to be a problem in the unmanaged portion of the control (or how I've wrapped it), and that exception is new to .net 2.0, it has some extra details (which hopefully get filled out) so this may shed some light on whats going wrong.

Code:

List<Message> messageCache = new List<Message>();
protected override void WndProc(ref Message m) {
    if(m.Msg == (WM_REFLECT + WM_NOTIFY)) {
        NmIPAddress ipInfo = (NmIPAddress)Marshal.PtrToStructure(m.LParam, typeof(NmIPAddress));
        if(ipInfo.Hdr.Code == -860) {
            if(values[ipInfo.Field] != ipInfo.Value) {
                values[ipInfo.Field] = ipInfo.Value;
                OnFieldChanged(new FieldChangedEventArgs(ipInfo.Field, ipInfo.Value));
            }
        }
    }
    try {
        messageCache.Add(Message.Create(m.HWnd, m.Msg, m.WParam, m.LParam));
        base.WndProc(ref m);
    } catch(AccessViolationException ave) {
        Debug.WriteLine("message: " + m.ToString());
        Debug.WriteLine("control handle: " + Handle.ToString());
        foreach(DictionaryEntry de in ave.Data) {
            Debug.WriteLine(string.Format("{0}={1}", de.Key, de.Value));
        }
        Debug.WriteLine("last 10 messasges:");
        for(int i = messageCache.Count-1; i > messageCache.Count-11; i--) {
            Debug.WriteLine(messageCache[i].ToString());
        }
    }
}

Offline

 

#8 23 Aug 2006 10:10 am

Jocker
Member
Registered: Aug 2006
Posts: 6
Website

Re: An IPAddress Control (the Win32 SysIPAddress32 control in C#)

the exception is thrown at the very beginning of the life of the control

Code:

last 10 messasges:
msg=0xe (WM_GETTEXTLENGTH) hwnd=0x222e0 wparam=0x0 lparam=0x0 result=0x0
msg=0x30 (WM_SETFONT) hwnd=0x222e0 wparam=0xffffffff9b0a3cac lparam=0x0 result=0x0
msg=0x31 (WM_GETFONT) hwnd=0x222e0 wparam=0x0 lparam=0x0 result=0x0
msg=0x210 (WM_PARENTNOTIFY) hwnd=0x222e0 wparam=0x216a0001 lparam=0x222f2 (WM_CREATE) result=0x0
msg=0x210 (WM_PARENTNOTIFY) hwnd=0x222e0 wparam=0x216a0001 lparam=0x222ee (WM_CREATE) result=0x0
msg=0x210 (WM_PARENTNOTIFY) hwnd=0x222e0 wparam=0x216a0001 lparam=0x62232 (WM_CREATE) result=0x0
msg=0x210 (WM_PARENTNOTIFY) hwnd=0x222e0 wparam=0x216a0001 lparam=0x62232 (WM_CREATE) result=0x0
msg=0x1 (WM_CREATE) hwnd=0x222e0 wparam=0x0 lparam=0x3b5dca4 result=0x0
msg=0x83 (WM_NCCALCSIZE) hwnd=0x222e0 wparam=0x0 lparam=0x3e0dccc result=0x0
msg=0x81 (WM_NCCREATE) hwnd=0x222e0 wparam=0x0 lparam=0x3e0dca4 result=0x0

it doesn't make much sense

Offline

 

#9 23 Aug 2006 12:18 pm

MadHatter
Administrator
From: Dallas TX
Registered: Jun 2006
Posts: 529
Website

Re: An IPAddress Control (the Win32 SysIPAddress32 control in C#)

I logged the messages that come in as they come in when the control is created, and my message stack is identical to yours with exception of the 10th message... you get the wm_gettextlength and I get 0xd3 (which I believe is wm_reflect + wm_paint).  so I tried a couple of things, like switching the 0xd3 message to a wm_gettextlength, and still nothing.  I tried removing the comctrl init, and still camt reproduce the error.

can you reproduce this on another machine? if not what makes the machine it crashes on different (permissions, memory, cpu, anything).

Offline

 

#10 23 Aug 2006 11:41 pm

Jocker
Member
Registered: Aug 2006
Posts: 6
Website

Re: An IPAddress Control (the Win32 SysIPAddress32 control in C#)

I haven't still had a chance to try it on other machines, but I took a Spy++ like application and looked at the differences of your wrapper control and the 'original' one that can be seen in the connection property window.
Well, it turns out that forcing these Style and StyleEx the exception is not thrown anymore.

Code:

CreateParams cp = base.CreateParams;
cp.ClassName = "SysIPAddress32";
cp.Height = 23;
cp.Style = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
cp.ExStyle = WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE | WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
return cp;

Now I'm more confused than before.
I think I'll just avoid passing to base.WndProc() the WM_GETTEXTLENGTH message since it seems to appear out of order and anyway it doesn't make sense for the SysIPAddress32 control
Thanks.

Last edited by Jocker (23 Aug 2006 11:42 pm)

Offline

 

#11 24 Aug 2006 12:51 am

MadHatter
Administrator
From: Dallas TX
Registered: Jun 2006
Posts: 529
Website

Re: An IPAddress Control (the Win32 SysIPAddress32 control in C#)

hrm... guess I should define the styles as well...

does it happen w/ this one?

Code:

/******************************************************/
/*          NULLFX FREE SOFTWARE LICENSE              */
/******************************************************/
/*  IPAddressControl                                  */
/*  by: Steve Whitley                                 */
/*   2004 NullFX Software                            */
/*                                                    */
/* NULLFX SOFTWARE DISCLAIMS ALL WARRANTIES,          */
/* RESPONSIBILITIES, AND LIABILITIES ASSOCIATED WITH  */
/* USE OF THIS CODE IN ANY WAY, SHAPE, OR FORM        */
/* REGARDLESS HOW IMPLICIT, EXPLICIT, OR OBSCURE IT   */
/* IS. IF THERE IS ANYTHING QUESTIONABLE WITH REGARDS */
/* TO THIS SOFTWARE BREAKING AND YOU GAIN A LOSS OF   */
/* ANY NATURE, WE ARE NOT THE RESPONSIBLE PARTY. USE  */
/* OF THIS SOFTWARE CREATES ACCEPTANCE OF THESE TERMS */
/*                                                    */
/* USE OF THIS CODE MUST RETAIN ALL COPYRIGHT NOTICES */
/* AND LICENSES (MEANING THIS TEXT).                  */
/*                                                    */
/******************************************************/


namespace NullFX.Controls {
    using System;
    using System.Net;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Drawing;
    [StructLayout(LayoutKind.Sequential)]
    public struct Nmhdr {
        public IntPtr HWndFrom;
        public UIntPtr IdFrom;
        public int Code;
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct NmIPAddress {
        public Nmhdr Hdr;
        public int Field;
        public int Value;
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct InitCommonControlsEX {
        public int dwSize;
        public int dwICC;
    }
    public enum IPField { OctetOne = 0, OctetTwo = 1, OctetThree = 2, OctetFour = 3 }
    public delegate void FieldChangedHandler(object sender, FieldChangedEventArgs e);
    public class FieldChangedEventArgs : EventArgs {
        private int _field, _value;
        public int Field {
            get { return _field; }
        }
        public int Value {
            get { return _value; }
        }
        public FieldChangedEventArgs(int field, int value)
            : base() {
            _field = field;
            _value = value;
        }
    }
    public class IPAddressControl : TextBox {
        private const int WM_NOTIFY = 0x004E,
            WM_USER = 0x0400,
            WM_REFLECT = WM_USER + 0x1C00,
            IPM_SETRANGE = (WM_USER + 103),
            IPM_GETADDRESS = (WM_USER + 102),
            IPM_SETADDRESS = (WM_USER + 101),
            IPM_CLEARADDRESS = (WM_USER + 100),
            IPM_ISBLANK = (WM_USER + 105),
            ICC_INTERNET_CLASSES = 0x00000800,
            CS_VREDRAW = 0x0001,
            CS_HREDRAW = 0x0002,
            CS_DBLCLKS = 0x0008,
            CS_GLOBALCLASS = 0x4000,
            WS_CHILD = 0x40000000,
            WS_VISIBLE = 0x10000000,
            WS_TABSTOP = 0x00010000,
            WS_EX_RIGHT = 0x00001000,
            WS_EX_LEFT = 0x00000000,
            WS_EX_RTLREADING = 0x00002000,
            WS_EX_LTRREADING = 0x00000000,
            WS_EX_LEFTSCROLLBAR = 0x00004000,
            WS_EX_RIGHTSCROLLBAR = 0x00000000,
            WS_EX_NOPARENTNOTIFY = 0x00000004,
            WS_EX_CLIENTEDGE = 0x00000200;
        private int[] values = new int[4];
        bool initialized = false;
        public event FieldChangedHandler FieldChanged;
        public IPAddressControl()
            : base() {
            for(int i = 0; i < 4; i++)
                values[i] = 0;
        }
        [DllImport("comctl32")]
        static extern bool InitCommonControlsEx(ref InitCommonControlsEX lpInitCtrls);

        protected virtual void OnFieldChanged(FieldChangedEventArgs e) {
            if(FieldChanged != null) FieldChanged(this, e);
        }
        protected override CreateParams CreateParams {
            get {
                if(!initialized) {
                    InitCommonControlsEX ic = new InitCommonControlsEX();
                    ic.dwSize = Marshal.SizeOf(typeof(InitCommonControlsEX));
                    ic.dwICC = ICC_INTERNET_CLASSES;
                    initialized = InitCommonControlsEx(ref ic);
                }
                if(initialized) {
                    CreateParams cp = base.CreateParams;
                    cp.ClassName = "SysIPAddress32";
                    cp.Height = 23;
                    cp.ClassStyle = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS | CS_GLOBALCLASS;
                    cp.Style = WS_CHILD | WS_VISIBLE | WS_TABSTOP | 0x80;
                    cp.ExStyle = WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE;
                    if(this.RightToLeft == RightToLeft.No || (RightToLeft == RightToLeft.Inherit && Parent.RightToLeft == RightToLeft.No)) {
                        cp.ExStyle |= WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
                    } else {
                        cp.ExStyle |= WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR;
                    }
                    return cp;
                } else {
                    return base.CreateParams;
                }
            }
        }
        public bool SetIPRange(IPField field, byte lowValue, byte highValue) {
            if(!initialized) return false;
            Message m = Message.Create(Handle, IPM_SETRANGE, (IntPtr)((int)field), MakeRange(lowValue, highValue));
            WndProc(ref m);
            return m.Result.ToInt32() > 0;
        }
        public System.Net.IPAddress IPAddress {
            get {
                return IPAddress.Parse(base.Text);
            }
        }
        public bool IsBlank {
            get {
                if(!initialized) return !(base.Text.Length > 0);
                Message m = Message.Create(Handle, IPM_ISBLANK, IntPtr.Zero, IntPtr.Zero);
                WndProc(ref m);
                return m.Result.ToInt32() > 0;
            }
        }
        new public void Clear() {
            if(!initialized) {
                base.Clear();
                return;
            }
            Message m = Message.Create(Handle, IPM_CLEARADDRESS, IntPtr.Zero, IntPtr.Zero);
            WndProc(ref m);
        }
        private System.Net.IPAddress GetIpAddress(IntPtr ip) {
            if(!initialized) return IPAddress.None;
            return new IPAddress(ip.ToInt64());
        }
        private IntPtr MakeRange(byte low, byte high) {
            return (IntPtr)((int)((high << 8) + low));
        }
        protected override void WndProc(ref Message m) {
            if(initialized && m.Msg == (WM_REFLECT + WM_NOTIFY)) {
                NmIPAddress ipInfo = (NmIPAddress)Marshal.PtrToStructure(m.LParam, typeof(NmIPAddress));
                if(ipInfo.Hdr.Code == -860) {
                    if(values[ipInfo.Field] != ipInfo.Value) {
                        values[ipInfo.Field] = ipInfo.Value;
                        OnFieldChanged(new FieldChangedEventArgs(ipInfo.Field, ipInfo.Value));
                    }
                }
            }
            base.WndProc(ref m);
        }
    }
}

I basically have what you've posted but added the RTL logic style assignment (which doesnt affect most of us) and the classstyle values.

whats weird though, is that these are the default styles values on my machine...  can you set a breakpoint on:

CreateParams cp = base.CreateParams;

and inspect base.CreateParams to see if the styles are different than what they're being set to here?

Offline

 

#12 24 Aug 2006 8:07 am

Jocker
Member
Registered: Aug 2006
Posts: 6
Website

Re: An IPAddress Control (the Win32 SysIPAddress32 control in C#)

does it happen w/ this one?

no, with this one it does not crash.

Styles created 'normally' on my machine (leaving unaltered Style and ExStyle)
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x00000192
WS_EX_CLIENTEDGE | WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR

styles forced by your new code:
WS_CHILD | WS_VISIBLE | WS_TABSTOP | 0x00000128
WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE | WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR

styles found on the standard SysIPAddress32 control:
WS_CHILD | WS_VISIBLE | WS_TABSTOP | 0x00000128
WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE | WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR

debug complete smile

Offline

 

#13 24 Aug 2006 7:12 pm

MadHatter
Administrator
From: Dallas TX
Registered: Jun 2006
Posts: 529
Website

Re: An IPAddress Control (the Win32 SysIPAddress32 control in C#)

thanks man.  I'll update my code in the article.  thanks for helping out!

Offline

 



© 2003 - 2017 NullFX
Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License