IPC windows service windows forms - winforms

I have an IPC problem. I have created into a windows service a NamedPipeServer:
serverPipe = new NamedPipeServerStream(Constants.PIPE_NAME, PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
Thread thread = new Thread(new ThreadStart(pipeWork));
thread.Start();
where pipeWork is
private static void pipeWork()
{
try
{
byte[] buffer = new byte[1024];
while (true)
{
if (!serverPipe.IsConnected)
serverPipe.WaitForConnection();
int nr = serverPipe.Read(buffer, 0, buffer.Length);
String str=Encoding.Default.GetString(buffer);
…
}
}
catch (Exception ex)
{
}
}
and into a Windows forms I have the client
clientPipe = new NamedPipeClientStream(".", PhotoServiceClassLibrary.Constants.PIPE_NAME, PipeDirection.InOut,PipeOptions.Asynchronous);
clientPipe.Connect();
clientPipe.ReadMode = PipeTransmissionMode.Message;
pipeThread=new Thread(new ThreadStart(pipeWork));
pipeThread.Start();
where pipeWork is
private void pipeWork()
{
try
{
while (true)
{
using (StreamReader sr = new StreamReader(clientPipe))
{
string message;
while ((message = sr.ReadLine()) != null)
{
…
}
}
}
}
catch (Exception ex)
{
}
}
I want when the service begin an action to disable a ContextMenuStrip from the windows forms, for that the service writes a message into a StreamWriter sw:
StreamWriter write = null;
write = new StreamWriter(serverPipe);
if (serverPipe.IsConnected)
{
write.Write(message);
write.Flush();
}
The code is correct because I created for testing another windows forms which implements the same things like the windows service and the communication between
windows forms pipe server -> windows forms pipe client is working well.
The problem is that the windows form - client pipe doesn't receive the message from windows service - server pipe.
I know that WCF can be a better idea but i want to understand why is not working at low-level IPC. Why? I've seen an very strange behavior. My service interact 2 times with the windows forms:
1.My service is designed for downloading some photos. When he begin download he sends a message to the windows forms to announcing him that.
2.When i stop the service he sends a message to windows forms and he stops also.
i've just discovered that both messages arrive at windows agent only after the service is stoped. Can someone explain why?

I hope this isn't your real code. It's good that you've got try/catch blocks around the code of your ThreadStart handlers (otherwise an exception would just quietly delete the thread). However, if you're not logging the exception in the catch block, then it's really just as bad.
You've got a mystery (server doesn't receive message), and you're hiding information (an exception has occurred). If you weren't hiding information, you might have the answer for your mystery (server doesn't receive message because an exception has occurred).

I'm trying to implement the same thing.
I noticed you're passing the PipeTransmissionMode.Message enumeration in the NamedPipeServerStream (serverPipe) constructor. That means the stream will contain strings.
But in pipeWork, you're reading them in as an array of bytes.
Look in the example in this article on MSDN:
http://msdn.microsoft.com/en-us/library/system.io.pipes.namedpipeclientstream.aspx

Related

How to detect URI activation on a WPF desktop package (WAP) after it has already launched?

I have a WPF desktop application that is MSIX-packaged using a Windows Application Package (WAP) project. I already know how to launch my WPF desktop app the first time using URI activation, by calling AppInstance.GetActivatedEventArgs() and then analyzing the arguments:
if (activatedEventArgs.Kind == ActivationKind.Launch)
{
if (((LaunchActivatedEventArgs)activatedEventArgs).Arguments == "myactivationcode")
// .. do something
}
But if a user runs the URI activation a 2nd time, while my app is already launched, I have learned that a new instance of my app is launched. This doesn't happen with UWP apps, just desktop apps. I can kill the 2nd instance to follow a desired singleton pattern, but what I want is for the first instance of my WPF app to get some event that lets it know to come back into view.
Things I've researched that have no answers that I can see:
How to handle URI activation in a Windows Application Packaging Project?
How can I handle file activation from a WPF app which is running as UWP?
https://learn.microsoft.com/en-us/windows/uwp/launch-resume/handle-uri-activation#step-3-handle-the-activated-event
Does any such API or event exist for URI re-activation? Or do I need to do some other form of IPC, like named pipes or WCF on the 2nd instance of my app? Any help here would be greatly appreciated.
But if a user runs the URI activation a 2nd time, while my app is already launched, I have learned that a new instance of my app is launched.
Whether a second instance is launched depends on the implementation of your custom Main method.
In your second link, there is a link to blog post and a code example that demonstrates how to prevent another instance from being launched.
It uses named pipes to communicate with the already running app instance and passes a serialized IActivatedEventArgs to it:
[STAThread]
static void Main(string[] args)
{
IActivatedEventArgs activatedEventArgs = AppInstance.GetActivatedEventArgs();
using (Mutex mutex = new Mutex(false, AppUniqueGuid))
{
if (mutex.WaitOne(0, false))
{
new Thread(CreateNamedPipeServer) { IsBackground = true }
.Start();
s_application = new App();
s_application.InitializeComponent();
if (activatedEventArgs != null)
s_application.OnProtocolActivated(activatedEventArgs);
s_application.Run();
}
else if (activatedEventArgs != null)
{
//instance already running
using (NamedPipeClientStream namedPipeClientStream
= new NamedPipeClientStream(NamedPipeServerName, AppUniqueGuid, PipeDirection.Out))
{
try
{
namedPipeClientStream.Connect(s_connectionTimeout);
SerializableActivatedEventArgs serializableActivatedEventArgs = Serializer.Serialize(activatedEventArgs);
s_formatter.Serialize(namedPipeClientStream, serializableActivatedEventArgs);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, string.Empty, MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}
}
Does any such API or event exist for URI re-activation?
No
Or do I need to do some other form of IPC, like named pipes or WCF on the 2nd instance of my app?
Yes. Again, please refer to the mentioned blog post and accompanied code sample.

C# communicating with Arduino COM access denied

I'm working with a fingerprint sensor on Arduino, but sometimes, on runtime, my WPF app throws an exception on sp.Open() saying "COM3" Access denied"
Here's the code on c#:
public string ConfigPort()
{
SerialPort sp = new SerialPort();
sp.BaudRate = 9600;
sp.PortName = AutodetectArduinoPort();
sp.Open();
string s = "";
while (true)
{
s = sp.ReadLine();
Console.WriteLine(s);
return s;
}
}
Here's the AutodetectArduinoPort method:
public string AutodetectArduinoPort()
{
ManagementScope connectionScope = new ManagementScope();
SelectQuery serialQuery = new SelectQuery("SELECT * FROM Win32_SerialPort");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(connectionScope, serialQuery);
try
{
foreach (ManagementObject item in searcher.Get())
{
string desc = item["Description"].ToString();
string deviceId = item["DeviceID"].ToString();
if (desc.Contains("Arduino"))
{
return deviceId;
}
}
}
catch (ManagementException e)
{
/* Do Nothing */
}
return null;
}
Any solution??
This happens quite a lot with Arduino, personally I think there's a problem with the FTDI driver....certainly wouldn't be the first issue with them. What I do when this happens is physically unplug the device from the USB port, wait for the notification sound from Windows and then plug it back in again. This seems to "reset" the port and force whatever is holding it open to release it, and you're good to go again. You may need to do this quite a bit over time, so the only other tip I have is to use a cheap USB hub so that you wind up wearing out the port pins on that rather than your expensive laptop/desktop.
The error you're getting means that the port is already open. Make sure that you only call ConfigPort() once, and after you're done processing data from the Arduino, close the port with sp.Close(). I would suggest converting sp into a global variable, and subscribing to the OnClosing event of your WPF window, so you can close the port when the user closes the application.

How to use WPF UserControls or Windows from inside Visual FoxPro 9

I have a very, very large and complex Visual FoxPro 9 application. I'd like to rewrite portions of this application in WPF with the ultimate goal of completing cutting over a couple of years from now. I've spent a considerable amount of time searching google and stackoverflow for an end to end "hello world" type sample of how to implement this with COM interop. Found bits and pieces but nothing complete that shows both the FoxPro side and the WPF side.
My gut tells me I'm likely to run into issues with XAML resources, third party controls, or other normal functionalities of a WPF app if I try to run it via COM Interop.
So, two questions. Can anyone point me to an small end to end sample that either launches WPF windows from FoxPro or lets me drop WPF user controls on a FoxPro form? Or am I right with my concerns of potential interop issues and should avoid this altogether? If so, is there a recommended way for these two executables to communicate with each other?
I have absolutely no idea whether you can run wpf inside visual FoxPro. I would guess you'd have to write it as an activex.
I recently did some work extending a MS Access app.
My wpf app is completely separate and runs alongside the ms access app.
I communicated between the two using MS Message Queue - which is a com component.
Maybe this sort of approach could work for you.
When I wanted to show a screen in wpf from access I added a piece of xml to the local message queue.
The wpf app listens for these messages, casts them to objects which tells it which screen to show and gives it any parameters.
MS Access subscribes to the received message event on the message queue and that way it can tell when the wpf window closes and the user is done.
This was intended to use the strangler pattern to gradually replace functionality in the old access app.
Here's some code for the queuelistener that drives everything. The various pop classes are deserialised from the message and I build that as a string in access.
internal class QueueListener
{
public const string qFromMadge = #".\private$\XXXXQ";
public static string qToMadge = #".\private$\XXXXReturnQ";
private MessageQueue mq;
internal QueueListener()
{
try
{
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
SubscribeHandler();
var mqSend = setUpQueue(qToMadge);
mqSend.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.InnerException.Message);
}
}
private MessageQueue setUpQueue(string qName)
{
MessageQueue q;
if (MessageQueue.Exists(qName))
{
q = new MessageQueue(qName);
}
else
{
q = MessageQueue.Create(qName);
}
q.ResetPermissions();
q.SetPermissions("Everyone", MessageQueueAccessRights.FullControl, AccessControlEntryType.Set);
q.Purge();
return q;
}
private void ReceiveMsgCompleted(Object source, ReceiveCompletedEventArgs asyncResult)
{
MessageQueue mq = (MessageQueue)source;
Message m = mq.EndReceive(asyncResult.AsyncResult);
m.Formatter = new XmlMessageFormatter(new[] { "XXXX.Popaaaa, XXXX"
, "XXXX.Popbbbb, XXXXX"
, "XXXX.Popcccc, XXXX"
, "XXXX.Popdddd, XXXX"
});
((BasePopView) m.Body).Pop();
mq.BeginReceive();
}
public void UnsubscribeHandler()
{
if (mq == null)
{
return;
}
mq.Close();
mq.ReceiveCompleted -= new ReceiveCompletedEventHandler(ReceiveMsgCompleted);
mq = null;
}
public void SubscribeHandler()
{
if(mq != null)
{
return;
}
mq = setUpQueue(qFromMadge);
mq.ReceiveCompleted += ReceiveMsgCompleted;
mq.BeginReceive();
}

Win App using Background worker process running on Terminal Server goes Non responsive

There is a Win app tool(C#) running at terminal server which is used to download mails, process the attachment in it and update its UI. Downloading and processing of mail attachments is done using the Background Worker process which also responsible for updating the UI with mails and attachments total and processed count at that instance. There is a timer which ticks to re-initializes the same background worker process after specified duration and look for new mails.
All works fine till the time I am logged in RDC, but when I lock the system (Window key+L) or switch users and comeback to regain the same session the tool is stuck/non responsive, it happens even if I lock and unlock the system instantaneously. I used another process monitoring tool which initially showed child threads getting created and exited periodically but after it is stuck no activity is shown.
I have no clue why is it happening, is window messing is stopped or UI Controls handle are lost or or or....
Following are the chunks of code I am using:
private void tmrScheduler_Tick(object sender, EventArgs e)
{
Application.DoEvents();
if (bgwMailParser == null || (!bgwMailParser.IsBusy && !objfeMailImportNParse.Is_Parsing))
{
bgwMailParser = new BackgroundWorker();
bgwMailParser.DoWork += new DoWorkEventHandler(objfeMailImportNParse.opLoadCommonData);
bgwMailParser.DoWork += new DoWorkEventHandler(objfeMailImportNParse.StartMailImport);
if (HireCraft.Properties.Settings.Default.Close_App_After_Parsing)
bgwMailParser.RunWorkerCompleted += new RunWorkerCompletedEventHandler(opCloseApplication);
bgwMailParser.RunWorkerCompleted += new RunWorkerCompletedEventHandler(opDisposeWorker);
bgwMailParser.RunWorkerAsync();
}
Application.DoEvents();
}
below method handles the events raised by bgWorker process
private delegate void Del_updateParsedCounter(Int64 del_MailCount, Int64 del_AttchCount);
private void UpdateParsedCounter(Int64 MailCount, Int64 AttchCount)
{
try
{
if (lblMailParsedCount.InvokeRequired)
{
Del_updateParsedCounter objUpdateParsedCounter = new Del_updateParsedCounter(UpdateParsedCounter);
this.Invoke(objUpdateParsedCounter, new object[] { MailCount, AttchCount });
}
else
{
lblMailParsedCount.Text = MailCount.ToString();
lblAttchSavedCount.Text = AttchCount.ToString();
}
}
catch (Exception ex)
{
Debug.Assert(false, ex.Message, ex.StackTrace);
}
}
I identified solution to issue but forgot that I raised a question here which wasn't answered.
Well issue was the background worker thread declaring a UIControl deep down somewhere in the code.
When a thread creates a UIControl it also registers itself with SystemEvents.UserPreferenceChanged event which notifies color, theme, screen size changes, system lock/unlock etc. and to respond to which parent thread requires a message pump lacking in background worker thread, the event invoke waits for a (never coming) response causing the application to hang or act non-responsive.
http://support.microsoft.com/kb/943139 link to Microsoft support explains the same.

WinForm Application stop running and freeze windows

I'm new to Windows development.
I've developed a WinForm application that communicate with a serial device and plot data on a chart.
The application should run 24h a day 7/7. The code is executed correctly, but after some hours of execution the UI freeze with a non responsive OS (I have to turn off the pc and restart it).
Serial class (using System.IO.Ports) execute read and write operations on separate thread.
This scenario make me think to a non correct cross-thread call from my serial class to UI. Reading Microsoft documentation and other questions i think i fixed the error but no way, the app continue to freeze the OS.
Write operation send a request character every 100ms to the board via serial, i'm using System.Threading.Timer to do that cause this operation will not interact with UI.
//Initialization
WriteTimer = new Timer(Write, COMport.IsOpen, 5000, 100);
// callback function
public static void Write(object state)
{
if ((bool) state)
{
try
{
COMport.Write("^");
}
catch (Exception exc)
{
ErrorLogger.WriteTxtLog(DateTime.Now,exc.ToString());
}
}
}
The serial board reply to the request char with a string of 10 bytes, to read the message I'm using the DataReceived event handler form IO.Ports, that is also execute on a separated thread, the received data will be elaborated and than passed to UI with a event handler delegate with args declared on the main form class. I pass the form control to the serial class to make a safe thread call.
// FormControl is passed in the constructor of the serial class:
public Form1 FormControl;
private void COMport_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort port = (SerialPort) sender;
byte[] buffer = new byte[10];
try
{
for (int i = 0; i < buffer.Length && buffer[i]!=3 ; i++)
{
buffer[i] = (byte) port.ReadByte();
}
SerialDataArgs args = checkDataReceived(buffer);
if (!args.error)
{
FormControl.Invoke(FormControl.drItem, new SerialDataArgs(...));
}
else
{
FormControl.Invoke(FormControl.drItem, new SerialDataArgs(0,0,true));
ErrorLogger.WriteTxtLog(DateTime.Now, "");
}
}
catch (Exception exc)
{
ErrorLogger.WriteTxtLog(DateTime.Now, exc.ToString());
}
}
UI thread (Form1 class):
SerialClass Serial = null;
public delegate void DataReceived(SerialDataArgs args);
public DataReceived drItem;
void ConnectCOM()
{
// COM READ
if (Serial == null)
{
Serial = new SerialClass(param.comName, this //this should be the FORM CONTROL);
if (Serial.Open)
{
...
drItem += HandleSeriaData;
}
else
{
...
}
}
}
//EventHandler
private void HandleSeriaData(SerialDataArgs args)
{
if (!args.error)
{
Work(args...); // in the work method i'll update labels, drawGraph,....
}
else
{
if (!Serial.Open) RecoverySerial();
}
}
Maybe the error is not here, but in front of Windows crashing it seems to me the only interested part. Sorry for my bad English, hope I made a correct/non duplicate question.
Use Control.BeginInvoke instead of Control.Invoke
From my experience, usually problems with System.IO.Ports.SerialPort cause only the UI to freeze, not the OS, and are caused by a deadlock when trying to update the UI from the SerialPort .DataReceived event using Control.Invoke and the UI thread itself tries to access the SerialPort object for example to close it. In this case there can be a deadlock when the UI thread is waiting for the SerialPort DataReceived thread to complete and the DataReceived thread is waiting for the UI thread to complete the Control.Invoke. To overcome these kinds of problems, it is better to use Control.BeginInvoke so the DataReceived thread does not wait for the UI thread.
Use lock to synchronize access to shared resources
When accessing the same object from different threads, use lock to synchronize data access. None synchronized data access can cause all different weird problems.
Check if the problem is with the serial port driver or connection
When the UI freezes and the OS becomes unresponsive, try to remove the serial-port device and see if the OS becomes responsive. If so, the problem may not be in the application but in the serial port driver or connection.
Hope this helps

Resources