Monday, July 14, 2008

Cross-thread operation not valid: Control 'name' accessed from a thread other than the thread it was created on

If you ever got the exception bellow and don't know how to avoid it, then this post is for you.
System.InvalidOperationException: Cross-thread operation not valid: Control 'TextBox1' accessed from a thread other than the thread it was created on.


Lets take a look at some code which actually throws such exception:

using System;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        int _iProgress = 0;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            progressBar1.Minimum = 0;
            progressBar1.Maximum = 100;
            progressBar1.Step = 1;
            progressBar1.Value = 0;

            Thread thread = new Thread(new ThreadStart(SomeThread));
            thread.Start();
        }

        private void SomeThread()
        {
            // Some process
            while (_iProgress < 100)
            {
                _iProgress++;
                progressBar1.PerformStep();
                Thread.Sleep(1000);
            }

            // [..]            
        }
    }
}

Execution of line progressBar1.PerformStep() will produce an exception.
The problem is that you cannot access the control from threads other than on which it was created on.

This can be solved by adding a delegate and further invoke it from thread.

Download sample source (Visual Studio 2008) - 11 KB
using System;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        int _iProgress = 0;
        private delegate void ProgressHandler();
        ProgressHandler updateHandler = null;

        public Form1()
        {
            InitializeComponent();
            updateHandler = new ProgressHandler(UpdateData);
        }

        void UpdateData()
        {
            progressBar1.PerformStep();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            progressBar1.Minimum = 0;
            progressBar1.Maximum = 100;
            progressBar1.Step = 1;
            progressBar1.Value = 0;

            Thread thread = new Thread(new ThreadStart(SomeThread));
            thread.Start();
        }

        private void SomeThread()
        {
            // Some process
            while (_iProgress < 100)
            {
                _iProgress++;

                // call the UpdateData method via the updateDataHandler so that we
                // update the UI on the UI thread
                Invoke(updateHandler);

                Thread.Sleep(100);
            }

            // [..]            
        }
    }
}

Sunday, July 6, 2008

Getting GPS location from bluetooth GPS device in Windows Mobile 5

Microsoft provides an interface for Windows Mobile devices to interact with built-in GPS receiver via GPS Intermediate Driver Interface. I faced with a problem when tried to connect GPS receiver connected via bluetooth. I could not start GPS device properly using GPSOpenDevice function, despite it returns an valid handler.

[...]
if (gps_handle == NULL) {
gps_handle = GPSOpenDevice(NULL, NULL, NULL, 0);
}

if (gps_handle == NULL)
return E_FAIL;

return S_OK;
[...]


A little bit history. Windows Mobile 5 introduced a GPS Intermediate Driver to allows multiple applications to share one GPS device. Before, if one app had the GPS COM port open, no other app could use it. But the Intermediate Driver creates a virtual COM port that multiplexes the real GPS port, and can handle multiple client apps simultaneously.

Windows Mobile 5 allows to configure the Intermediate Driver via Control Panel.



The control panel lets you set the Hardware Port, which is the real port the GPS device is actually on, and the Program Port, which is the virtual COM port the Intermediate Driver exposes. It is called the Program Port because it is the COM port that GPS programs talk to.

GPSOpenDevice will work properly if GPS device hardware port configured properly in control panel settings. On some Windows Mobile devices it is hidden from control panel. Fortunately it can be unhidden by going into the registry and changing "Hide" key value from "1" to "0" under HKEY_LOCAL_MACHINE\ControlPanel\GPS Settings.



References:
GPS Intermediate Driver Functions http://msdn.microsoft.com/en-us/library/ms850331.aspx