Hidlibrary event threads - c#

I'm using mikeobriens HIDLibrary for communicating with a sensor we make.
It's all working, and I have it so it re-enumerates if the device is unplugged then reconnected.
The problem I have is that each time it's reconnected, a new HidLibrary.HidDeviceEventMonitor.DeviceEventMonitor Worker Thread is created, and if the system is run like this for a long period, many threads are created. How can I kill these threads when the device is disconnected?

I believe there is a kind of bug if the HidLibrary.
If you look closer at the HidDevice class you may found that HidDevice.CloseDevice doesn't actually stop event monitoring.
There are two ways to fix it.
Either call Dispose instead of CloseDevice in your application:
//_device.CloseDevice(); - dispose will close device automatically
_device.Dispose();
Or set the flag MonitorDeviceEvents to false after CloseDevice call:
_device.CloseDevice();
_device.MonitorDeviceEvents = false;
I would prefer the first one.
N.B. Also be sure that you don't keep a reference to the disconnected device.

This didn't work for me because I'm using the blocking call Device.ReadReport(AddressOf OnReport). If I simply set the device to NULL (to get rid of the reference), then the next scan throws an exception.
To get around this, here's what I did:
Public Class myDevice
Private Device As HidDevice
Private isConnected as Boolean
Public Sub Close()
If Not Device Is Nothing Then
Device.CloseDevice()
Device.MonitorDeviceEvents = False
End If
isConnected = False
End Sub
Sub OnReport(Report As HidReport)
If isConnected = False Then
Device.Dispose()
Device = Nothing
Return
End If
' Do stuff with the data
' ...
' ...
' Wait for more data.
Device.ReadReport(AddressOf OnReport)
End Sub
End Class
So after closing a device, the thread is left in a state where it is still waiting for input. BUT ... I've set a flag to indicate that the device has been closed (Device.isConnected did not work for me, so I created my own flag). The next event received by the closed thread detects that the device is no longer "connected", so it disposes the device, de-references the device, and returns without calling ReadReport.

Related

Moving the current process window to the front

I am calling a thread every hour to take a screenshot.
but the issue is with activating the window or moving the window to the front.
if there are other apps in the front then while taking the screenshot they appear in the front.
Whats going on?
<Runtime.InteropServices.DllImport("user32.dll")>
Private Function SetForegroundWindow(ByVal hWnd As IntPtr) As Integer
End Function
<Runtime.InteropServices.DllImport("user32.dll")>
Private Function ShowWindow(ByVal hWnd As IntPtr, ByVal nCmdShow As Integer) As IntPtr
End Function
Public Sub TakeScreenshot()
Dim thread As New Threading.Thread(AddressOf TakeScreenShotThread)
thread.Start()
End Sub
Public Function TakeScreenShotThread() As Integer
Dim proc As Process = Process.GetCurrentProcess
Call SetForegroundWindow(proc.MainWindowHandle)
Call ShowWindow(proc.MainWindowHandle, 5)
'GIVE IT TIME TO DISPLAY THE APP AND ACTIVATE WINDOW
Dim t = Threading.Tasks.Task.Run(Async Function()
Await Threading.Tasks.Task.Delay(TimeSpan.FromMilliseconds(200))
Return 1
End Function)
t.Wait()
'SAVE SCREENSHOT IMAGE CODE HERE
End Function
Unfortunately(or if one thinks from the user's point of view fortunately) SetForegroundWindow is not an unconditional "make this window the foremost/active one" command.
It has a set of restrictions:
The system restricts which processes can set the foreground window. A process can set the foreground window only if one of the following conditions is true:
The process is the foreground process.
The process was started by the foreground process.
The process received the last input event.
There is no foreground process.
The process is being debugged.
The foreground process is not a Modern Application or the Start Screen.
The foreground is not locked (see LockSetForegroundWindow).
The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
No menus are active.
So while there are some not recommended ways to overcome this restriction, under normal circumstances, unless one of those conditions is true, SetForegroundWindow won't work.
P.S.: Also, recommended reading - https://devblogs.microsoft.com/oldnewthing/20090220-00/?p=19083
P.S.1: While this restriction is probably the reason why the original solution fails, I'd also like to point that there is a chance that proc.MainWindowHandle can be IntPtr.Zero or be a stale handle (from some starting window or etc.) and that you do not check return values from the called WIN API functions, that is both very important and may actually assist in troubleshooting the issue...

Server function to be ran once for all users

Good evening,
In my SignalR application I have a javascript timer that is ran for all users "simultaneously". At the end of this timer, a server function is called, and this is where this problem starts.
As the function is called at the end of the timer, every connected user calls it at the same time, which is unnecessary because it will return the same output for all connected users. Being a logically complex function, having the server run it unnecessarily for all users adds up to be a great resource waste.
How can I make it so that it is ran only once (maybe the first time it is called (until the next timer stops))?
Thank you in advance
You could make use of GlobalHost.ConnectionManager.GetHubContext. This will allow you to get any hub context and then trigger Clients.All.YourFunction on that context. That will send send a message to all connected clients subscribed to that hub.
You will need to have a background process that runs every at the time your JavaScript function fires (by the way, relying on all your clients to call a JavaScript function simultaneously is really not a good idea; different client locations and different machine performance will mean they're not likely to be simultaneous).
The following is assuming that you're just running this on a single server. If you're going to be deploying this to a web farm, then you'll need to use a Database value to ensure you don't repeat the same work, or set up a particular server instance to be responsible for doing the calls (otherwise you'll end up with one call per server).
Create a process that runs in the Background (I'm sticking with a simple thread here, I actually use HangFire for this, but this will suffice for the example), e.g. On App_Start
Thread thread = new Thread(new ThreadStart(YourFunction));
thread.Start();
Then create YourFunction which will be responsible for your client calls:
private bool Cancel = false;
private void YourFunction()
{
do
{
string foo = "Foo";
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<YourHub>();
context.Clients.All.SendYourMessage(foo);
Thread.Sleep(10000);
}
while(!Cancel)
}
And then on the client, just handle the message from the hub:
youyHub.client.sendYourMessage = function(message)
{
// message == "Foo"
};

Is it good practice to put try-catch in a loop until all statements in the try block is executed without any exceptions?

I was trying to develop a multicast receiver program and socket initialization was done as shown below:
public void initializeThread()
{
statuscheckthread = new Thread(SetSocketOptions);
statuscheckthread.IsBackground = true;
}
private void Form1_Load(object sender, EventArgs e)
{
rxsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
iep = new IPEndPoint(IPAddress.Any, 9191);
rxsock.Bind(iep);
ep = (EndPoint)iep;
initializeThread();
statuscheckthread.Start();
}
public void SetSocketOptions()
{
initializeThread(); //re-initializes thread thus making it not alive
while (true)
{
if (NetworkInterface.GetIsNetworkAvailable())
{
bool sockOptnSet = false;
while (!sockOptnSet)
{
try
{
rxsock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("224.50.50.50")));
rxsock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 64);
sockOptnSet = true;
}
catch
{
//Catch exception here
}
}
}
break; // Break out from loop once socket options are set
}
}
When my PC is not connected to a network, SetSocketOption method was throwing exception and even after network is connected,
I was unable to receive data because socket options are not set.
To avoid this I used a thread which runs in the background checking
for network availability and once network is available, it sets the socket options.
It works properly in some PC's but in some others, NetworkInterface.GetIsNetworkAvailable()
returned true before network got connected
(while network was being identified) .
So, to make sure Socket options are set, I used a bool variable sockOptnSet
which is set as
true if all the statements in the try block is executed as shown inside the method public void SetSocketOptions()
This program works fine in all PC's I tried, but I am doubtful about how much I can rely on this to work.
My questions are:
1) Is this good practice?
2) If not, what are the possible errors or problems it may cause? And how can I implement it in a better way?
Is this a good practice?
No, not a good practice. The vast majority of exceptions, including your first one, fall in the category of vexing exceptions. Software is supposed to work, worked well when you tested it, but doesn't on the user's machine. Something went wrong but you do not know what and there isn't anything meaningful that you can do about it. Trying to keep your program going is not useful, it cannot do the job it is supposed to do. In your case, there's no hope that the socket is ever going to receive data when there is no network. And, as you found out, trying to work around the problem just begets more problems. That's normal.
If this is bad practice, how can I implement it in a better way?
You need help from a human. The user is going to have to setup the machine to provide a working network connection. This requires a user interface, you must have a way to tell a human what he needs to do to solve your problem. You can make that as intricate or as simple as you desire. Just an error message, a verbatim copy of the Exception.Message can be enough. Writing an event handler for the AppDomain.CurrentDomain.UnhandledException event is a very good (and required) strategy. Microsoft spent an enormous amount of effort to make exception messages as clear and helpful as possible, even localizing them for you in the user's native language, you want to take advantage of that. Even if the exception message is mystifying, a quick Google query on the message text returns hundreds of hits. With this event handler in place, you don't have to do anything special. Your program automatically terminates and your user knows what to do about it.
You can certainly make it more intricate, you discovered that SetSocketOption() is liable to fail right after the network becomes available but works when you wait long enough. So this is actually an error condition that you can work around, just by waiting long enough. Whether you should write the code to handle this is something that you have to decide for yourself. It is something you write when you have enough experience with the way your program behaves, you never write it up front. Usually as a result from feedback from the users of your program.
Some good advice in the comments, lets' expand on it.
Firstly, I would put all this socket code in to its' own class, outside of the form. This makes it its' own entity and semantically easier to understand. This class could have a property Initialised, which is initially set to false. The first thing you do in your form is call an Initialise method on this class which attempts to set socket options and catches the relevant exceptions if the network is not available. If it is available, we set our Initialised property to true.
If not available, we set a single timeout (see System.Threading.Timer) that calls this same function (potentially with a retry count) after 'x' seconds. Once again we'll find ourselves back in this Initialise function, perhaps with a retry count mentioned at the beginning. Once again, if it is available, we're good - if not, set the timer again. Eventually, after 'x' retries if we're not initialised we can throw an exception or set some other failure property to indicate that we can't proceed.
Your Form class can periodically check (or hook in to an event) to determine whether the socket is now ready for communication. In case of failure you can gracefully quit out, or because our class is nice and abstracted, attempt to start the whole process again.

Detecting unexpected socket disconnect

This is not a question about how to do this, but a question about whether it's wrong what I'm doing. I've read that it's not possible to detect if a socket is closed unexpectedly (like killing the server/client process, pulling the network cable) while waiting for data (BeginReceive), without use of timers or regular sent messages, etc. But for quite a while I've been using the following setup to do this, and so far it has always worked perfectly.
public void OnReceive(IAsyncResult result)
{
try
{
var bytesReceived = this.Socket.EndReceive(result);
if (bytesReceived <= 0)
{
// normal disconnect
return;
}
// ...
this.Socket.BeginReceive...;
}
catch // SocketException
{
// abnormal disconnect
}
}
Now, since I've read it's not easily possible, I'm wondering if there's something wrong with my method. Is there? Or is there a difference between killing processes and pulling cables and similar?
It's perfectly possible and OK to do this. The general idea is:
If EndReceive returns anything other than zero, you have incoming data to process.
If EndReceive returns zero, the remote host has closed its end of the connection. That means it can still receive data you send if it's programmed to do so, but cannot send any more of its own under any circumstances. Usually when this happens you will also close your end the connection thus completing an orderly shutdown, but that's not mandatory.
If EndReceive throws, there has been an abnormal termination of the connection (process killed, network cable cut, power lost, etc).
A couple of points you have to pay attention to:
EndReceive can never return less than zero (the test in your code is misleading).
If it throws it can throw other types of exception in addition to SocketException.
If it returns zero you must be careful to stop calling BeginReceive; otherwise you will begin an infinite and meaningless ping-pong game between BeginReceive and EndReceive (it will show in your CPU usage). Your code already does this, so no need to change anything.

Terminating a Form while COM DataReceived Event keeps fireing. C#

I'm currently having a problem, which seems to be related to closing a Form, while a scale, which is connected through a Serial Connection keeps sending data (about 3 packages per sek).
I handle new data over the DataReceived-Event (handling itself might be uninteresting for this issue, since I'm just matching data) Keep an eye on the COM_InUse variable and the allowFireDataReceived check.):
private void COMScale_DataReceived(object sender, EventArgs e)
{
if (allowFireDataReceived)
{
//set atomar state
COM_InUse = true;
//new scale:
if (Properties.Settings.Default.ScaleId == 1)
{
strLine = COMScale.ReadTo(((char)0x2).ToString());
//new scale:
Regex reg = new Regex(Constants.regexScale2);
Match m = reg.Match(strLine);
if (m.Success)
{
strGewicht = m.Groups[1].Value + m.Groups[2];
double dblComWeight;
double.TryParse(strGewicht, out dblComWeight);
dblScaleActiveWeight = dblComWeight / 10000;
//add comma separator and remove zeros
strGewicht = strGewicht.Substring(0, 1) + strGewicht.Substring(1, 2).TrimStart('0') + strGewicht.Substring(3);
strGewicht = strGewicht.Insert(strGewicht.Length - 4, ",");
//write to textbox
ThreadSafeSetActiveScaleText(strGewicht);
COMScale.DiscardInBuffer();
//MessageBox.Show(dblScaleActiveWeight.ToString(), "dblScaleActiveWeight");
}
}
//free atomar state
COM_InUse = false;
}
}
The COM_InUse variable is a global bool and "tells" if there is a current process of handling data.
The allowFireDataReceived is also a global bool and if set to false will lead to no extra handling of the data which has been sended.
My problem now is the following:
It seems that Eventhandling is a separate Thread, which leads to a deadlock on klicking the Cancel-Button since the COM_InUse will never turn to false, even if the Event was handled (see end of COMScale_DataReceived, where COM_InUse is set to false).
While setting allowFireDataReceived = false works perfectly (no handling any more), as I said: the while loop will not terminate.
private void bScaleCancel_Click(object sender, EventArgs e)
{
allowFireDataReceived = false;
while (COM_InUse)
{
;
}
if (!COM_InUse)
{
ret = 1;
SaveClose();
}
}
When I comment out the while-block I have to click twice on the button, but it works without a crash. Since this very user unfriendly, I'm searching for an alternative way to safely close the window.
Info:
Simply closing (without checking if the COM-Data was processed) lead to a fatal crash.
So, maybe someone can explain to me what exactly causes this problem or can provide a solution to this. (Maybe one would be to trigger the Cancel-Clicking Event again, but that is very ugly)
Greetings!
I count on you :)
//edit:
Here is the current code of
private void ThreadSafeSetActiveScaleText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.lScaleActive.InvokeRequired)
{
SafeActiveScaleTextCallback d = new SafeActiveScaleTextCallback(ThreadSafeSetActiveScaleText);
this.Invoke(d, new object[] { text });
}
else
{
this.lScaleActive.Text = text;
}
}
ThreadSafeSetActiveScaleText(strGewicht);
Yes, the DataReceived event runs on a threadpool thread. You already knew that, you wouldn't have called it "ThreadSafe" otherwise. What we can't see is what is inside this method. But given the outcome, it is highly likely that you are using Control.Invoke().
Which is going to cause deadlock when you loop on COM_InUse in code that runs on the UI thread. The Control.Invoke() method can only complete when the UI thread has executed the delegate target method. But the UI thread can only do that when it is idle, pumping the message loop and waiting for Windows messages. And invoke requests. It cannot do this while it looping inside the Click event handler. So Invoke() cannot complete. Which leaves the COM_InUse variable for ever set to true. Which leaves the Click event handler forever looping. Deadlock city.
The exact same problem occurs when you call the SerialPort.Close() method, the port can only be closed when all events have been processed.
You will need to fix this by using Control.BeginInvoke() instead. Make sure the data is still valid by the time the delegate target starts executing. Pass it as an argument for example, copying if necessary.
Closing the form while the scale is unrelentingly sending data is in general a problem. You'll get an exception when you invoke on a disposed form. To fix this, you'll need to implement the FormClosing event handler and set e.Cancel to true. And unsubscribe the DataReceived event and start a timer. Make the Interval a couple of seconds. When the timer Ticks, you can close the form again, now being sure that all data was drained and no more invokes can occur.
Also note that calling DiscardInBuffer() is only good to randomly lose data.

Categories

Resources