OpenFileDialog works from app but not from a spawned thread after use InvokeMember to load assembly / class
-
I've stripped my problem down to the bare minimum. I've got a form that, in response to user action, needs to display the OpenFileDialog dialog. When this form is started "normally" i.e. using Application.Run, the dialog appears. When this form is started via reflection it fails. Fails in this case means that the code successfully runs all the way to the actual OpenFileDialog.ShowDialog call -- ShowDialog is stepped into but the dialog never appears and the call never returns. Here's the code: The direct app:
using UiLibrary;
namespace DirectApp
{
static class Program
{
[STAThread]
static void Main ()
{
Application.EnableVisualStyles ();
Application.SetCompatibleTextRenderingDefault (false);
Application.Run (new Form1 ());
} } }The indirect app:
namespace IndirectApp
{
public partial class DummyFormToLaunchTheRealUI
{
public DummyFormToLaunchTheRealUI () { InitializeComponent (); }private void button1\_Click (object sender, EventArgs e) { Assembly abs = Assembly.LoadFile (@"C:\\temp\\tester\\UiLibrary\\bin\\debug\\UiLibrary.dll"); Type startType = abs.GetType ("UiLibrary.Startup", true); object startLib = startType.InvokeMember ("", BindingFlags.CreateInstance, null, null, new object\[0\]); startType.InvokeMember ("Run", BindingFlags.InvokeMethod, null, startLib, new object\[0\]);
} } }
The library:
namespace UiLibrary
{
public class Startup
{
public void Run ()
{
Thread runThread = new Thread (new ThreadStart (ActualWork));
runThread.Start ();
}private void ActualWork () { Form1 f = new Form1 (); f.ShowDialog (); }
}
public partial class Form1 : Form
{
public Form1 () { InitializeComponent (); }private void button1\_click (object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog (); // this field always correct ofd.InitialDirectory = Environment.ExpandEnvironmentVariables (@"%USERPROFILE%\\Downloads"); // doesn't change if call ShowDialog with no paramters ofd.ShowDialog (this);
} } }
I've got to show Form1 from the library in its own thread since I want IndirectApp to remain responsive to UI. This is stripped down - in my real code Form1 is much more complex, successfully launching its own forms and doing other stuff regardless of which method is use to fire it up. Visual Studio 2012 using .NET 3.5 on
-
I've stripped my problem down to the bare minimum. I've got a form that, in response to user action, needs to display the OpenFileDialog dialog. When this form is started "normally" i.e. using Application.Run, the dialog appears. When this form is started via reflection it fails. Fails in this case means that the code successfully runs all the way to the actual OpenFileDialog.ShowDialog call -- ShowDialog is stepped into but the dialog never appears and the call never returns. Here's the code: The direct app:
using UiLibrary;
namespace DirectApp
{
static class Program
{
[STAThread]
static void Main ()
{
Application.EnableVisualStyles ();
Application.SetCompatibleTextRenderingDefault (false);
Application.Run (new Form1 ());
} } }The indirect app:
namespace IndirectApp
{
public partial class DummyFormToLaunchTheRealUI
{
public DummyFormToLaunchTheRealUI () { InitializeComponent (); }private void button1\_Click (object sender, EventArgs e) { Assembly abs = Assembly.LoadFile (@"C:\\temp\\tester\\UiLibrary\\bin\\debug\\UiLibrary.dll"); Type startType = abs.GetType ("UiLibrary.Startup", true); object startLib = startType.InvokeMember ("", BindingFlags.CreateInstance, null, null, new object\[0\]); startType.InvokeMember ("Run", BindingFlags.InvokeMethod, null, startLib, new object\[0\]);
} } }
The library:
namespace UiLibrary
{
public class Startup
{
public void Run ()
{
Thread runThread = new Thread (new ThreadStart (ActualWork));
runThread.Start ();
}private void ActualWork () { Form1 f = new Form1 (); f.ShowDialog (); }
}
public partial class Form1 : Form
{
public Form1 () { InitializeComponent (); }private void button1\_click (object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog (); // this field always correct ofd.InitialDirectory = Environment.ExpandEnvironmentVariables (@"%USERPROFILE%\\Downloads"); // doesn't change if call ShowDialog with no paramters ofd.ShowDialog (this);
} } }
I've got to show Form1 from the library in its own thread since I want IndirectApp to remain responsive to UI. This is stripped down - in my real code Form1 is much more complex, successfully launching its own forms and doing other stuff regardless of which method is use to fire it up. Visual Studio 2012 using .NET 3.5 on
I suspect your background thread needs to be an STA thread. Try changing your
Startup.Run
method:public void Run()
{
Thread runThread = new Thread(ActualWork);
runThread.ApartmentState = ApartmentState.STA;
runThread.Start();
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
I suspect your background thread needs to be an STA thread. Try changing your
Startup.Run
method:public void Run()
{
Thread runThread = new Thread(ActualWork);
runThread.ApartmentState = ApartmentState.STA;
runThread.Start();
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
And the prize goes to Richard!!! That fixed the issue. Must be something that the common file dialogs need that your plain old ordinary user-created form doesn't. THANKS!!!:thumbsup: Judy
Be wary of strong drink. It can make you shoot at tax collectors - and miss. Lazarus Long, "Time Enough For Love" by Robert A. Heinlein
-
I suspect your background thread needs to be an STA thread. Try changing your
Startup.Run
method:public void Run()
{
Thread runThread = new Thread(ActualWork);
runThread.ApartmentState = ApartmentState.STA;
runThread.Start();
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer