Handling custom messages in windows compact framework 3.5 using windows mobile handheld 6.5 on a POCKETPC

485 Views Asked by At

I'm updating an existing application that scans barcodes and is written in VB.net running on windows compact framework 3.5. The scanner is a POCKETPC running windows mobile handheld 6.5. I have added code that uses Asynchronous TCP sockets in a class module. The sockets code is reading and sending data to and from a buffer pool. I now need to “inform” the GUI form that data has been received from the TCP socket and is ready for processing. Because the two processes are running on different threads I realise I cannot access the GUI controls directly. I therefore create a windows message (WM_CUSTOMMSG = &H400) and then use “SENDMESSAGE”. There is an existing WndProc sub (Protected Overrides Sub WndProc(ByRef msg As Microsoft.WindowsCE.Forms.Message)) that handles the WM_DECODEDATA for the scanner message. I added in code to now also process the WM_CUSTOMMSG message I am creating. The WM_CUSTOMMSG is arriving at the WndProc and I am able to display a MessageBox and write a log file, but any changes made to the GUI controls just disappear. I tried to start a forms timer but this also has no effect. Code for the WM_DECODEDATA message updates the GUI controls perfectly. What am I missing / done wrong?

Public Class frmHome
    Public SockReceiveMsg As Microsoft.WindowsCE.Forms.Message
    Public Sub New()
      Private yy As Integer = 0
      Private xx As Integer = 0
      InitializeComponent()
      Me.MsgWin = New MsgWindow(Me)
      ' Add any initialization after the InitializeComponent() call.
      SockReceiveMsg = Microsoft.WindowsCE.Forms.Message.Create(MsgWin.Hwnd, MsgWindow.WM_CUSTOMMSG, New IntPtr(xx), New IntPtr(yy))
end class

Private Sub ReceiveCallback(ByVal ar As IAsyncResult)
'This is the async call back sub
  MessageWindow.SendMessage(frmHome.SockReceiveMsg)   
end sub

Protected Overrides Sub WndProc(ByRef msg As Microsoft.WindowsCE.Forms.Message)
    Dim rc As Integer
    Dim ar() As String
    If msg.Msg = WM_CUSTOMMSG Then
        Try
          MsgBox("restart timer")       'this displays
          Reader.ReaderEngineAPI.Beeper(8, "")   'a quick ok beep. this works
          frmHome.timer1.Enabled = False
          frmHome.timer1.Interval = 100
          frmHome.timer1.Enabled = True     
        Catch ex As Exception
            MsgBox("wndproc Error1: " & ex.Message)
        End Try
    End If
    'pass all messages onto the base processing. Here the windows ones get processed and our ones get cleared and the storage released
    MyBase.WndProc(msg)

End Sub
3

There are 3 best solutions below

0
C.Evenhuis On

I don't know if/what you're doing wrong, but you can probably do things alot easier. All Controls (including Forms) have an Invoke() method that you can call to let the framework deal with the windows messages.

This article describes it in a bit more detail, including the InvokeRequired property, which you can probably ignore if you know the data is sent from another thread.

If you do choose to handle these messages manually (since you already have the WndProc routine), be sure to catch all exceptions in the method that updates the GUI, and perhaps inspect the InvokeRequired to see if the control agrees that you can update it from that thread.

0
josef On

I would go with a delegate and an eventhandler on the thread code and use InvokeRequired with a custom delegate to update the GUI thread.

Handling custom message is not recommended. Or why does MS hide WndProc in WindowsCE.Forms? OTOH you may need to Refresh the controls that have been changed to let them know that they need to update. Do you use PostMessage or SendMessage. If later, that would block the thread code until the message is processed, which may block the GUI to update itself, if the WndProc itself uses SendMessage inside the code to handle the custom message.

Private Sub UpdateTextBox(ByVal sender As Object, ByVal e As EventArgs)
    '---delegate to update the textbox control
    txtMessagesArchive.Text += str
End Sub

That would be called from a background thread in the same class via:

Me.Invoke(New EventHandler(AddressOf UpdateTextBox))

Different ways to update GUI from background thread, but in C#

0
John Agar On

Thank you to all who provided answers. I had previously tried a delegate with invoke but this caused the system to crash. I spent over a week trying to find out what was wrong with the delegate code – I mean it is so simple, but was not successful. I then tried the WndProc route. Josef’s example in his answer showed me that the delegate must be in the same class as the backgound thread. I had placed the delegate in the form class. Once I put the delegate in the correct class it works perfectly. I have 50 years of experience in IT and programming and you can still learn. I am not going to try to get to the bottom of the WndProc problem. This is now academic as the delegate route is a better solution and is now working. Thank you