Thursday, December 27, 2007

sender or eventSender object, what is the point?

When looking at the MouseMove problem, I wandered over to the first argument passed to MouseMove, MouseDown, etc.

sender as System.Object (sometimes referred to as eventSender as System.Object).

What was the point of this this?  We never used it in our code, so why was it being passed?

From this article - http://www.informit.com/articles/article.aspx?p=102148&seqNum=3 I realized that you can use that argument to figure out the who called the function.  For example, if you have the MouseDown handle the call from 10 buttons, you can use the sender object to figure which button called the MouseDown routine.  What you need to do is convert (cast) it to an Control or a Button, and then you can get the Button's text.

Another use I found for this is if you manually call MouseDown, or manually call MouseMove.  In that past if we called a MouseMove event from the MouseDown routine, we just passed the sender from MouseDown to MouseMove.  Sample code below:

    Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
        Form1_MouseMove(sender, e)
    End Sub

At first I thought in MouseMove, we could use the sender object to see if the routine was called by code or by the Form.  But in MouseMove, when you look at the sender object, you cannot tell.  So one way to tell is do something like this:

    Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
        Form1_MouseMove("FromMouseDown", e)
    End Sub

Then in MouseMove, you can do the following:
    Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove
        If TypeOf sender Is String Then
          'Do Something, you can even test what the string value is
          Dim aString as String = DirectCast(sender, String)
             If aString = "FromMouseDown" Then
                MsgBox("FromMouseDown")
             End If
        End If
    End Sub



MouseMove put to rest

Ok, the problem initially seemed to be because of my trackball mouse.  After putting a workaround where i saved the position of the mouse in mousedown and in mousemove checked to see if the position was different, I just cleaned my trackball, and lo and behold the problem went away.  It seems that because my trackball was dirty, the mousemove event kept getting called, even though the position wasn't changing.

Wednesday, December 26, 2007

MouseMove oddity

So far the previous problem only occurs on my machine.  I have a trackball mouse, and this only occurs on my machine.  On a machine with a regular mouse, this does not occur.  Now it just might be my trackball mouse.

MouseMove event is always fired

I've always coded with the idea that the MouseMove event in VB.NET occurs when the mouse actually moves.  However, maybe its my machine, but I created a new project.  Added a MouseMove event to the form, with a Debug Statement.  This debug statement is always called, even when my mouse is not moving.  Odd.  I'm using .NET 2003.  The problems this causes are many if you assume the mousemove event should only be called when the mouse is actually moving.


Wednesday, December 19, 2007

Textbox ignores the first character if you set the CharacterCasing property in the KeyPress event

I had this situation where I had a Textbox on a Form, and in the KeyPress event, I set the CharacterCasing to either Upper or Lower depending on the field I was working on.  The problem I had was that the first character was getting ignored.  It turned out that the problem was that for some reason setting the CharacterCasing in the KeyPress event causes you to lose the first character.  The solution was to move the CharacterCasing block to the TextBox.Enter event. 

To recreate this error, open a form, add a textbox to the form.  Create a Keypress Event, and set the TextBox's CharacterCasing to True.  If you run the program and click in the textbox, and enter a value, the first value will be ignored.

The solution was to move it to the TextBox.Enter subroutine.

Tuesday, December 18, 2007

Avoid Memory Leaks with FromHBitmap and GetHbitmap - Continued

Ok, earlier I mentioned how to avoid memory leaks with FromHBitmap and GetHbitmap.  In the example I had a bitmap supplied by reference.  A key thing to realize (which I didn't at the time) is that the approach I presented can lead to broken pointers.  Example is below:

'Just say you have the following Picture box (FImage)
'If you do the following, abmp will point to the Image of FImage (you don't make a copy)
Dim abmp as Bitmap = FImage.Image
'If you then supply abmp to the function I mentioned in the earlier post.
'Then all of a sudden FImage.Image does not have any data and you get an error when you try to use it.

So be careful when using the code below.


Stop stickykey hell

This is from my manager:


I don't know if you ever accidentally get into Windows "Filterkeys" mode, but if you press both shift keys at once, or one shift key for 8 seconds, you go into an accessibility mode in text is selected.

If like me, you never ever ever want this to happen, go into Control Panel>Accessibility options>Keyboard>Filterkeys settings button>Uncheck "keyboard shortcut"

I turn off the rest of them too – I have absent-mindedly tapped the shift key a few times and gone into "StickyKey" hell.

Task Manager doesn't have Menu Bar or Tabs

Ok, not programmer related, but all of a sudden my Task Manager didn't have the Menu Bar or Tabs.  After a quick google search, it turns out that it is running in "Tiny Footprint Mode" and the solution is to double-click the border area again.  The enable it again, double-click the border around the tabs.

Monday, December 17, 2007

Avoid Memory Leaks with FromHBitmap and GetHbitmap

In VB6 we called .Handle to get a handle to an image, which I then passed to a C routine.  In order to get a handle to an image in VB.NET, I had to call GetHbitmap.ToInt32 to get a handle.  Then in order to get the image back from that call, I would call FromHBitmap.  Below is an example:

    Public Function DoSomething(ByRef hbmp As Bitmap) As Integer
        Dim returnVal As Integer
        Dim hbmp1 As IntPtr
        If Not hbmp Is Nothing Then
            hbmp1 = hbmp.GetHbitmap 'Get a handle to the image

            returnVal = DoSomethingInC(hbmp1.ToInt32) 'get an Integer Pointer to the Image which is passed to the C routine
            hbmp = Bitmap.FromHbitmap(hbmp1)
            Return returnVal
        Else
            Return MiscError
        End If
    End Function

Now when I did this, I had a memory leak with GetHBitmap and FromHBitmap.  You solve that by calling .Dispose and DeleteObject.  Highlighted below.

    Public Function DoSomething(ByRef hbmp As Bitmap) As Integer
        Dim returnVal As Integer
        Dim hbmp1 As IntPtr
        If Not hbmp Is Nothing Then
            hbmp1 = hbmp.GetHbitmap 'Get a handle to the image

            returnVal = DoSomethingInC(hbmp1.ToInt32) 'get an Integer Pointer to the Image which is passed to the C routine
            If Not hbmp Is Nothing Then hbmp.Dispose()
            hbmp = Nothing
            hbmp = Bitmap.FromHbitmap(hbmp1)
            DeleteObject(hbmp1)
            Return returnVal
        Else
            Return MiscError
        End If
    End Function

A couple of thoughts:
1.  Doing this slows down performance, as the calls to GetHbitmap and FromHBitmap is a lot slower than just calling Image.Handle (in VB6).  I still haven't figured out how to solve the performance hit.
2.  I still have issues with 8 bit images, as in VB.NET we do everything in 32 bit, and previously my C routines were working with 8 bits.  I still haven't figured out a workaround to this.


Avoid Memory Leaks with PictureBox

I had a situation where I had a memory leak with a PictureBox, I did something like this:
            Dim bm_out As New Bitmap(Width, Height)
            Dim gr_out As Graphics = Graphics.FromImage(bm_out)           
            gr_out.DrawImage(...)
            FullImage.Image = bm_out

Now everytime this block of code was called, when the New Bitmap was created we created a new block of memory.  When I left this function, I was constantly losing memory.  The reason for this is that FullImage.Image was pointing to a block of memory, and when I called FullImage.Image = bm_out, I pointed it to a new block of memory, and lost the pointer to the previous block of memory.  But that previous block of memory was still allocated.  So I had a memory leak.  The solution was this one line, before FullImage.Image = bm_out
            FullImage.Image.Dispose()

So the code like this did not have the memory leak.
            Dim bm_out As New Bitmap(Width, Height)
            Dim gr_out As Graphics = Graphics.FromImage(bm_out)           
            gr_out.DrawImage(...)
            FullImage.Image.Dispose()
            FullImage.Image = bm_out