I'm struggling with a legacy library (written in Delphi I think, no access to the source code). It comes with a C# Windows Forms demo application, in which it:
- Performs some basic usage of the legacy library in the main thread (get the version etc)
- Performs any 'real' usage triggered by user input with the C# ThreadPool. Outputting the thread ids shows that all relevant scenarios work without issues.
However, when replicating this in a console application, it just does not work.
- Executing relevant actions sequentially in the main thread -> ok
- Mimicking the demo app with simple initial calls in the main thread and actions in worker threads -> usually not ok
- Skipping main thread work and performing actions in worker threads -> usually only ok for the first thread doing work. Subsequent threads fail to perform the work correctly.
After a lot of head scratching I decided to create a super simple WPF app to see if that would make any difference. Well, it just works flawlessly ... I've put the redacted code at the bottom of my question.
Given that both the WPF app and the classical Windows Forms apps work without any issues, my main question is: what could cause this big difference regarding multithreaded libary usage between a Windows GUI app and a console app? To clarify: in my console app I tried many approaches, ThreadPool, Thread objects, Tasks, ... Nothing works reliably.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
string version = "";
Legacy.GetVersion(ref version);
this.status.Text = version;
}
void output(string output)
{
this.status.Dispatcher.Invoke( () => { this.status.Text += output; });
}
void connect(string ip, uint id)
{
var settings = new Settings();
settings.IPAddress = ip;
output($"thread {Environment.CurrentManagedThreadId} is connecting to device {id}");
var result = Legacy.Connect(id, settings);
output($"connect result for device {id} and thread {Environment.CurrentManagedThreadId}: " + Legacy.ResultString(result));
if (Legacy.Ok((uint)result))
{
var info = new Info();
result = Legacy.GetInfo(id, info);
output(info.DeviceId);
}
result = Legacy.Disconnect(id);
output("disconnect result: " + Legacy.ResultString(result));
}
private void Button_Click(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem((object bla) => connect("10.0.0.146", 1));
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem((object bla) => connect("10.0.0.139", 2));
}
}
}