Asynccallback in dll causes Form to freeze - c#

I have a form Form1 with a button and text box.
When I click on the button I should get some data from USB device.
For some reason it works correctly only about 2% (I was able to get 2 correct responses out of 100 clicks).
Here is the code for the Form1:
namespace Test_onForm1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Lib1.FindHID.TransferInputAndOutputReports(0xC0); //request specific data from USB device
}
}
}
The code handling USB communication is in DLL Lib1 (fragments of the code below):
namespace Lib1
{
public static class FindHID
{
private static void TransferInputAndOutputReports(UInt16 repType)
{
//some code here sending request to USB device... and then read what came from USB
ReadInput();
//some code here
}
// Read an Input report.
private static void ReadInput()
{
Byte[] inputReportBuffer = null;
inputReportBuffer = new Byte[MyHid.Capabilities.InputReportByteLength];
IAsyncResult ar = null;
if (fileStreamDeviceData.CanRead)
{
// RUNS UP TO THIS POINT and then Form1 freezes most of the time
fileStreamDeviceData.BeginRead(inputReportBuffer, 0, inputReportBuffer.Length, new AsyncCallback(GetInputReportData), inputReportBuffer);
}
}
private static void GetInputReportData(IAsyncResult ar)
{
// RARELY GETS HERE
Byte[] inputReportBuffer = null;
inputReportBuffer = (byte[])ar.AsyncState;
fileStremDeviceData.EndRead(ar); //waits for read to complete
// then code to update Form1
}
}
}
}
When it doesn't work it stops around fileStreamDeviceData.BeginRead and then Form1 freezes.
For testing I created a completely new project and instead of using a DLL I copied all DLL code to the Form1.
This option works perfectly fine 100% of the time.
So my question is why it doesn't work with DLL?
Update: when I get lucky and it start working then it works indefinitely until I close application. Then, I have to keep trying to get it to work again.
How to troubleshoot this problem?

Most likely the problem is that the code in EndRead is trying to update the form, but it's not on the UI thread. You have to synchronize with the UI thread, either by doing Form.Invoke or some way notifying the form that the data is ready so that the UI thread can do the update.

SOLVED!
Found on Microsoft website:
"The default implementation of BeginRead on a stream calls the Read method synchronously, which means that Read might block on some streams."
I was using .NET Framework 4.0 on Visual Studio 2010.
Decided to update to .NET Framework 4.5 which has Stream.ReadAsync method instead. However, I couldn't implement Stream.ReadAsync on Visual Studio 2010 (don't know the reason, maybe needs update to 2012?).
So, with updated Framework 4.5 I tried my code and it works ALL THE TIME EVERY TIME.

Related

Async/Await works in Windows Form application, but it shouldn't

Based on MSDN article following code shouldn't work in Windows Forms application and I'm pretty much certain, that it didn't work in past, but recently I've discovered, that in .NET framework 4.7.02558 it works.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void Test()
{
Console.WriteLine("One");
var d = DelayAsync();
Console.WriteLine("Three");
d.Wait();
Console.WriteLine("Five");
}
private async Task DelayAsync()
{
Console.WriteLine("Two");
await Task.Delay(1000);
Console.WriteLine("Four");
}
private void Button1_Click(object sender, EventArgs e)
{
Test();
}
}
Did I miss some a release log, or is something wrong (I mean right from user's perspective)?
Edit: An application should freeze after returning from awaited code because in Windows Forms is used CurrentContextSheduller.
Testing on 4.7.1 I get the following results:
One
Two
Three
Four, and Five never get displayed. It seems to be "not-working as intended" for me, as execution of await Task.Delay(1000); is blocking.
Discovered. The problem was caused by ReSharper Build & Run. For some reason, the build wasn't done and switching from ReSharper Build to Visual Studio build program behaves "correctly".
Latest build was done with .ConfigureAway(false), so that's a root cause of why it worked and shouldn't.

C# form is blocked after creation

I am creating a Form when a certain event occurs. I put this created Form into a static member of the class where it is created. I debugged the code and everything works fine but the Form stays blocked and the user can't do anything in this window. It just appears with a loading animation (see picture). So nothing in the opened window is clickable, you can't even close it.
class CallManagementObserver : CallObserver
{
private static FrmIncomingCall frmCurrentCall;
public CallManagementObserver()
{
}
public void callChangedEvent(CallEv[] events)
{
foreach (CallEv currentEvent in events)
{
switch (currentEvent.getID())
{
case TermConnRingingEv.ID:
// Incoming call
frmCurrentCall = new FrmIncomingCall(currentEvent);
frmCurrentCall.Show();
frmCurrentCall.Update();
break;
case CiscoCallInfoChangedEv.ID:
// User accepted external call on terminal
frmCurrentCall.Close();
break;
case TermConnActiveEv.ID:
// User is in call
frmCurrentCall.Close();
break;
case ConnDisconnectedEv.ID:
// Caller has hung up
frmCurrentCall.Close();
break;
default:
break;
}
}
}
}
}
As you can see above I wrote my own Form class whose code is here:
public partial class FrmIncomingCall : Form
{
Call incomingCall;
CallEv currentEvent;
public FrmIncomingCall(CallEv currentEvent)
{
InitializeComponent();
this.currentEvent = currentEvent;
this.incomingCall = currentEvent.getCall();
}
private void initGui()
{
Connection[] callConnections = incomingCall.getConnections();
Address caller = callConnections[1].getAddress();
lblIncomingCallSource.Text = caller.getName();
}
private void btnAcceptCall_Click(object sender, System.EventArgs e)
{
TermConnEv termConnEv = (TermConnEv)currentEvent;
TerminalConnection termConn = termConnEv.getTerminalConnection();
termConn.answer();
}
private void frmIncomingCall_Load(object sender, System.EventArgs e)
{
initGui();
}
}
When I show the Form via ShowDialog() it is usable but the program stops (since this is what dialogs are made for I guess).
Any ideas what I'm doing wrong? Nothing freezes, the program is running correctly.
Well, your application is poorly designed... It seems that you have no idea of what multithreading is and why you should use it.
If the application hangs forever, then either there is a deadlock (something like the dialog wait on the calling system and the calling system wait on the dialog).
As I have no idea what CallEv is and how it is intended to be used.
Well, if the calling system works and the UI is never updated, then obviously, you never let the UI have time to be updated because your UI thread is 100% of the time using the calling system or waiting on it.
That means that the calling system should probably be used from another thread and that you should have some communication between both threads...
It might also be possible that the calling system might be used in many different ways (as it would be the case for serial port and TCP communication) where one could use what fit most with his application.
Another problem with your code is that when you close a dialog, as far as I know it cannot be used anymore without recreating the dialog as the dialog would be disposed... So you would need to set the formCurrentCall to null and update any affected code. Alternatively, you might hide the form instead and show it again when required.
In any case, it is hard to help you because we don't have any idea of what is CallEv and other classes or events in your code. Also, we have no idea which code is executing when the UI is not responding (or updated). So the question do not have enough informations. In fact, such problem are way easier to debug using a debugger as it is far easier to see what code is run and which line of code take time to execute or even to see which code is not executed.

Powershell: Unable to interact with Form stored in a .Net Assembly

I'm just trying to learn this thing and in future, wanted to use it in one of my projects.
I have a small Form with a simple Text box, stored in a .Net dll (C#). And here is my class in this dll which contains methods to interact with this Form:
using System;
using System.Collections.Generic;
using System.Text;
namespace ClassLibrary1
{
public class Class1
{
static Form1 dlg = new Form1();
public static void ShowForm()
{
dlg.ShowIcon = true;
dlg.Show();
}
public static void SetText(string MyText)
{
dlg.Text = "Form Text ";
dlg.SetText(MyText);
}
}
}
Successfully loaded this form by referencing this dll into another C# application while calling its method i.e.:
private void button1_Click(object sender, EventArgs e)
{
ClassLibrary1.Class1.ShowForm();
}
And I was able to interact with the form perfectly.
Now loading same in Powershell using:
[Reflection.Assembly]::LoadFile("D:\Playing\ClassLibrary1\ClassLibrary1\bin\Debug\ClassLibrary1.dll")
[ClassLibrary1.Class1]::ShowForm()
Now this is loaded successfully at its default position, but I can't interact with this form i.e. I can't type in its Text Box, neither I can move or even close this form by clicking on its Close (x) button on right corner. Whenever I put my mouse on it, it becomes a HourGlass i.e. waiting for some process .
To verify if form is not hanged, I called SetText at Powershell prompt:
[ClassLibrary1.Class1]::SetText("String from Powershell")
and it worked fine. TextBox received this text properly, but still I can't interact with the form with my mouse.
I feel, I have to manually set its Window Handler i.e. System.Windows.Forms.IWin32Window.
But I don't know which Handler and how to achieve this?
Please guide .... Would really appreciate for any alternative tricks.
You can't show a form from PowerShell using Form.Show() method because it needs a message pump (and it's not provided by PowerShell host process).
Here what you can do to solve this issue:
Use Form.ShowDialog() or Application.Run(), your form will have its own message pump.
It'll be modal then you need to run it in another thread. I suggest to use a background thread and BeginInvoke() in your SetText() method.
Here code to do that (I won't change your code too much so I'll keep it as a singleton instance even if this prevents to display form multiple times). Code is just an example (I wouldn't suggest to use Thread Pool for this task) to illustrate the procedure.
public static void ShowForm()
{
if (dlg != null)
dlg.BeginInvoke(new MethodInvoker(delegate { dlg.Dispose(); }));
ThreadPool.QueueUserWorkItem(delegate(object state)
{
Application.Run(_dlg = new Form1());
});
}
public static void SetText(string text)
{
_dlg.BeginInvoke(new MethodInvoker(delegate { dlg.SetText(text); }));
}
In this way Form1 will be modal in another thread (with its own message pump) and your calling PowerShell thread won't be stopped. Communication between them is still possible via message dispatching (Invoke()/BeginInvoke()).
Please note that SetText() is now asynchronous, to make it synchronous just replace BeginInvoke() with Invoke().

Printing in windows service using background worker

I'm developing a Windows service that has to print some labels on a network printer.
Here http://msdn.microsoft.com/en-us/library/5ekk3hse.aspx it says that printing in Windows service using System.Drawing.Printing classes is not supported (or rather shouldn't be done).
This Print html document from Windows Service in C# without print dialog seems like the solution, but they say there that it requires .Net Framework 4.0, and I have to use 2.0 (or I can change it to 3.5 if I really, really have to, but then the client will have to upgrade which I want to avoid).
I also read that to print from Windows service on network printer the domain account is required for the service, which I'm using anyway, so that's not the problem.
Every setting for the printer will be set in .config file and I hope that because of this no user dialog will be appearing/needed.
My questions:
Will I be able to print directly from Windows service using BackgroundWorker? Or do I need to call another app (for example console application) from inside of my service and do the printing there (I've read on the net that some people use this solution but I didn't found any code example)
Also I'm not good with threading and working with BackgroundWorkers so can someone give me some example how can I do it (I have requests to print coming asynchronously. How can I print them without loosing any?). Is the BackgroundWorker the best solution or are there some better ways to do it?
I haven't tested printing from another thread, but one of these two options should work. You might have to modify the code to work with .Net 2 since I only use 3.5 Sp1 or 4.
Assuming you have a Print method and a Queue<ItemToPrint> where ItemToPrint is the class holding the print settings / information
public Queue<ItemToPrint> PrintQueue = new Queue<ItemToPrint>();
private BackgroundWorker bgwPrintWatcher;
public void SetupBackgroundWorker()
{
bgwPrintWatcher = new BackgroundWorker();
bgwPrintWatcher.WorkerSupportsCancellation = true;
bgwPrintWatcher.ProgressChanged += new ProgressChangedEventHandler(bgwPrintWatcher_ProgressChanged);
bgwPrintWatcher.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgwPrintWatcher_RunWorkerCompleted);
bgwPrintWatcher.DoWork += new DoWorkEventHandler(bgwPrintWatcher_DoWork);
bgwPrintWatcher.RunWorkerAsync();
}
void bgwPrintWatcher_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (!worker.CancellationPending)
{
// Prevent writing to queue while we are reading / editing it
lock (PrintQueue)
{
if (PrintQueue.Count > 0)
{
ItemToPrint item = PrintQueue.Dequeue();
// Two options here, you can either sent it back to the main thread to print
worker.ReportProgress(PrintQueue.Count + 1, item);
// or print from the background thread
Print(item);
}
}
}
}
private void Print(ItemToPrint item)
{
// Print it here
}
private void AddItemToPrint(ItemToPrint item)
{
lock (PrintQueue)
{
PrintQueue.Enqueue(item);
}
}
void bgwPrintWatcher_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Anything here will run from the main / original thread
// PrintQueue will no longer be watched
}
void bgwPrintWatcher_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Anything here will run from the main / original thread
ItemToPrint item = e.UserState as ItemToPrint;
// e.ProgressPercentage holds the int value passed as the first param
Print(item);
}

Library works when called in Form1, but not from anywhere else

I have this library http://www.codeproject.com/KB/cs/globalhook.aspx
I've downloaded it and compiled it to DLL.
At first I had a weird problem that it haven't worked in my project, but it did (in the exact same code) worked in the demo project, but it was fixed by applying what the following message said:
http://www.codeproject.com/KB/cs/globalhook.aspx?msg=3505023#xx3505023xx
Note: I'm working with .NET 4, VS 2010 Ultimate
Well, I have a file Form1.cs, which is my main form for my app.
I have other files: Client.cs, Script.cs, Keylogger.cs - no, it's not an evil keylogger - It's for a school presentation about security\antiviruses etc.
Keylogger.cs has one static class and here's the code:
public static class Keylogger
{
static private StreamWriter sw = null;
static private System.Timers.Timer t = null;
static public bool Started = false;
static public void Start(string Location)
{
Started = true;
sw = new StreamWriter(Location, true, Encoding.Default, 1);
HookManager.KeyPress += HookManager_KeyPress;
t = new System.Timers.Timer(3600000);
t.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => sw.WriteLine(Environment.NewLine + "1 HOUR PASSED");
t.Start();
}
static public void Stop()
{
if (!Started)
throw new Exception("Keylogger is not operating at the moment.");
Started = false;
HookManager.KeyPress -= HookManager_KeyPress;
t.Dispose();
sw.Dispose();
}
static private void HookManager_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 8)
sw.Write("{BACKSPACE}");
else
sw.Write(e.KeyChar);
}
}
The Client class isn't static - it manages a TCP connections with a server, and send all received data to Script.RunScript(string scr) (static method).
Well, Script.RunScript should invoke Keylogger.Start(string location) for some input (STARTLOGGING c:\log.txt)
And invoke Keylogger.Stop() for some input (STOPLOGGING)
Well, everything is good, it invokes Start, but it doesn't work.
It does the whole process, (timer, event, streamwriter etc) but when I press something - the whole computer freeze for a couple of seconds and nothing happened (it doesn't even invoke KeyPress) - it happens only the first time. any other time - it simply ignores my keypress.
THE FUNNY THING IS - if I call Start from my mainform (in the ctor, on a button click event) - IT DOES WORK ! without any lag.
I did try different events (MouseDoubleClick, MouseMove) and all had the same problem.
Thank you, Mark !
The delay followed by the UI getting responsive again is a strong sign of the underlying cause of the problem. You see Windows healing itself, noticing that the callback isn't being responsive. It automatically disables the hook.
The hard requirement you probably violate is that the SetWindowsHookEx() call must be made from a thread that pumps a message loop. So that Windows can break in on a keypress and call the callback. That works fine when you called the Start() method from a button click, the Click event runs on the UI thread of your program.
But probably not when you this call is made from a networking event. They tend to run on a threadpool thread. It isn't clear from your snippet, you didn't post the code. The generic fix for a problem like this is using Control.BeginInvoke() to marshal a call from a worker thread to the UI thread. You'll find a good description of it in the MSDN library article as well as many, many answers here at stackoverflow.com
Fwiw, the original code got broken due to changed behavior in the .NET 4 version of the CLR. It no longer fakes the native module for assemblies. The workaround is good enough, it only needs a valid module handle. The actual one doesn't matter since this is not a global hook.
I think your best bet is to not write to the network on UI events, but instead have your logger write to a local file or in-memory database or similar, and then have a timer that periodically writes the content of that message to the server. That way you can both send chunkier messages to the server (improving performance on both machines) as well as have the ability to run the network call on a background thread, which makes the UI feel snappier.

Categories