Wednesday, December 26, 2007

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