Having a problem here...not sure if it's something simple or not.
I'll be honest, threading is new to me so I'm not quite sure what the problem is here.
Let me explain the problem first and then I'll post some code.
I have a method that runs in a wizard called StartWizard(). The method is not a form method, but it does open and access forms to complete the wizard tasks. One of the methods that the StartWizard method calls is called InspectEnvironment() which runs two other methods that check to see if a .dll is registered and also scans the local computer and network for SQL servers that can be automatically detected.
I would like to have InspectEnvironment() run on a separate thread.
The InspectEnvironment() method is only called when the first step is shown in the wizard. The first step contains a few label controls, some picture boxes to indicate what task is currently being performed and a progress bar.
Before the InspectEnvironment() is called, the StartWizard() method shows an instance of the wizard container (an MDI form) and also calls another form inside of that container called Step1. Step1 is a form that contains all of the controls I mentioned.
The InspectEnvironment() method that needs to run on a separate thread needs to be able to access the controls on the Step1 form.
Earlier this morning the code was throwing exceptions saying that a thread was trying to access controls created on a different thread.
No problem...I checked into thread-safe calls and set up a delegate for the thread to access the controls.
The problem is I'm not getting any exception errors while in debug, it just...stops. I've tried stepping through the code and I have found where it stops. Maybe someone here could shed some light on this for me?
Heres some code in some (hopefully) logical order:
public class Start
{
// Region Map
//
// Globals
// - Accessors
// Methods
#region Globals
//does the OleExtension exist on the localhost
private static bool _OleExtensionExists;
//the list of found SQL servers on the network
private static DataTable _FoundServers;
//initialize the wizard step forms
private static Main _WizardWindow;
private static Step1 _step1;
//thread reset
private static AutoResetEvent resetThreadEvent = new AutoResetEvent(false);
#region Accessors
/// <summary>
/// Permits access to the bool information on if the OleExtension exists that the system needs for accessing
/// MS Access database files
/// </summary>
public static bool OleExtensionExists
{
get { return _OleExtensionExists; }
set { _OleExtensionExists = value; }
}
/// <summary>
/// Permits access to a list of remote and local SQL Server instances that are supported
/// </summary>
public static DataTable FoundServers
{
get { return _FoundServers; }
set { _FoundServers = value; }
}
public static Main WizardWindow
{
get { return _WizardWindow; }
set { _WizardWindow = value; }
}
public static Step1 step1
{
get { return _step1; }
set { _step1 = value; }
}
#endregion
#endregion
#region Methods
public void StartWizard()
{
//initialize all wizard step forms
WizardWindow = new Main(this);
step1 = new Step1(this);
//show the Main Wizard Window
WizardWindow.Show();
Application.DoEvents();
//show step1
step1.MdiParent = WizardWindow;
step1.Show();
Application.DoEvents();
//inspect the environment on a separate thread
ThreadPool.QueueUserWorkItem(new WaitCallback(InspectEnvironment), resetThreadEvent);
Application.DoEvents();
resetThreadEvent.WaitOne();
/*
* We need to determine which wizard to run based on the local and network environment information
* that was returned by the InspectEnvironment() method
* We have a few scenarios:
* 1) at least one SQL Server exists and so does the OleExtension
* 2) at least one SQL Server exists only
* 3) the OleExtension exists only
* 4) neither an SQL Server or the OleExtension exist
*/
int i = 0; //this is just here as a breakpoint
}
/// <summary>
/// Inspects the local machine and network and sets wizard global variables
/// </summary>
private void InspectEnvironment(object threadSignal)
{
//see if the Microsoft.ACE.OLEDB.12.0 extension is registered
bool OleExtensionExists = FindOleDBExtension();
//provide UX feedback
if (OleExtensionExists)
{
//the extension is available
//step1.pictureBoxStep1.Image = Properties.Resources.ok;
//this is where the problems start...
step1.SetImages(step1.pictureBoxStep1, Properties.Resources.ok);
}
else
{
//the extension is not available
step1.pictureBoxStep1.Image = Properties.Resources.messagebox_warning;
}
//provide UX feedback
step1.pictureBoxStep2.Image = Properties.Resources.reload;
Application.DoEvents();
//get a list of SQL servers on the local network
//call the FindSqlServers method a few times to make sure all instances on the network are awake and can
//respond
FindSqlServers();
FindSqlServers();
DataTable FoundServers = FindSqlServers();
//provide UX feedback
step1.pictureBoxStep2.Image = Properties.Resources.ok;
Application.DoEvents();
//exit thread
((AutoResetEvent)threadSignal).Set();
}
}
public partial class Step1 : Form
{
//initialize access to the Wizard Controller
Start WizardController;
public Step1(Start wizardController)
{
InitializeComponent();
WizardController = wizardController;
}
// Region Map
//
// Globals
// Methods
#region Globals
//SetImages callback
public delegate void SetImagesCallback(PictureBox imageToChange, Image newImage);
#endregion
#region Methods
public void SetImages(PictureBox imageToChange, Image newImage)
{
if (imageToChange.InvokeRequired)
{
//called from a different handle, invoke this method
//initialize our delegate
SetImagesCallback d = new SetImagesCallback(this.SetImages);
//invoke the delegate
//this is where the application stops responding...
this.Invoke(d, new object[] { imageToChange, newImage });
}
else
{
//change the image
imageToChange.Image = newImage;
}
}
#endregion
}