Message Handler Stops Seeing Responses? - c#

As a workaround for a dumb issue, I have a separate application do my SharePoint file syncing that I launch as a separate process and communicate via WriteLine and ReadLine. After the third Sync command, it seems the Process executes it (as evidenced by a separate log file), but my SyncToolMessageHandler is no longer getting alerted to its responses even with forced flushes on the external process. If I run the program myself and send the exact same commands, no issue in the console window. So why do I seem to lose my message handler? The Process handle is still alive and well.
I also see this in my debugger on SyncToolProcess. It shows this before I send the first WriteLine so I'm not sure what it's talking about but maybe it's a clue? I'm establishing the process/callbacks and sending commands from an "Update" loop in Unity and the responses are obviously asynchronous whenever the process responds. Is that somehow a problem?
Sender:
public void LaunchSyncTool()
{
SyncToolProcess = new Process();
SyncToolProcess.StartInfo.FileName = "SyncProcess.exe";
SyncToolProcess.StartInfo.Arguments = SpecialArguments;
SyncToolProcess.StartInfo.UseShellExecute = false;
SyncToolProcess.StartInfo.RedirectStandardOutput = true;
SyncToolProcess.StartInfo.RedirectStandardInput = true;
SyncToolProcess.StartInfo.RedirectStandardError = true;
SyncToolProcess.StartInfo.CreateNoWindow = true;
SyncToolProcess.OutputDataReceived += new DataReceivedEventHandler(SyncToolMessageHandler);
SyncToolProcess.ErrorDataReceived += new DataReceivedEventHandler(SyncToolMessageHandler);
SyncToolProcess.Start();
SyncToolProcess.BeginOutputReadLine();
SyncToolProcess.BeginErrorReadLine();
SyncToolProcess.StandardInput.WriteLine("Sync File1 File2");
}
// Super simplified, but the ping and pong works great until about the 3rd sync.
public void SyncToolMessageHandler(object sender, DataReceivedEventArgs e)
{
if (e.Data == "Good")
{
Debug("Received 'Good', Sending Command");
SyncToolProcess.StandardInput.WriteLine("Sync File3 File4");
}
else Debug(e.Data); // Exceptions come up Null for some reason, but not seeing them here :-\
// SyncToolProcess.HasExited is always false
}
Receiver:
while (true)
{
string inputCmd = await Console.In.ReadLineAsync();
Debug("Received \"" + inputCmd + "\"");
try
{
string[] split = inputCmd.Split(' ');
switch (split[0])
{
case "Sync":
Sync(split);
break;
case "Quit":
Debug("Quitting");
return;
default:
Debug("Unknown Request: " + inputCmd);
break;
}
}
catch (Exception e)
{
Error(e.Message + "\n" + e.StackTrace);
}
Status("Good");
}

Ugh. The problem was the Unity Editor. If I build the program first it no longer misses the callbacks. Not exactly an answer for using the Editor, but at least I know the code is right!

Related

Autoconnect with Microsoft Display Adapter using Windows.Devices.WiFiDirect

First, I have extensively read through Autoconnect to MS Wireless display on Windows 10 and tried basically every solution. (I did technically get the AutoHotKey solution working, and in fact did that before even researching. But, I feel like that's kind of unprofessional and surely there is some API that can connect to this thing.) After going through all of this, I just started reading through the different namespaces. Finally, I found Windows.Devices.WiFiDirect. This gave me the most progress I've been able to get, which is, it begins to connect and says so on screen, then an exception stating that the device is unreachable occurs. Very infuriating.
Can anyone explain exactly what is happening here? It seems like this should be the proper way to connect my screen to this device, but it is just not working. Code below, it's pretty short and straightforward.
Edit:
Based on Roy Li's suggestion, I attempted to use a different overload of the socket.ConnectAsync method. This actually did have an effect but I am still receiving an exception, although a different one. The method now attempts to connect for longer but still fails out, this time with a "connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond" exception. Could this mean there is some sort of secret handshake that Window's OS is using when connecting to this device? If so, this might be a dead end. The code has been updated below.
static async Task Main()
{
string id = null;
string prefix = "MicrosoftDisplayAdapter";
WiFiDirectDevice device;
StreamSocket socket = new StreamSocket();
try
{
DeviceInformationCollection devInfoCollection = await DeviceInformation.FindAllAsync(WiFiDirectDevice.GetDeviceSelector());
foreach (DeviceInformation devInfo in devInfoCollection)
{
if (devInfo.Name.StartsWith(prefix))
{
id = devInfo.Id;
}
}
device = await WiFiDirectDevice.FromIdAsync(id);
var endpointPairCollection = device.GetConnectionEndpointPairs();
await socket.ConnectAsync(endpointPairCollection[0].RemoteHostName, "50001"); //This line begins connecting to the display but ultimately fails
}
catch (Exception e)
{
//device unreachable exception
}
}
I finally found something along the lines of what I need. I came across https://social.msdn.microsoft.com/Forums/en-US/7608d127-d864-436a-802e-472fd55cc02c/use-projectionmanager-from-net-framework?forum=csharpgeneral, which gave me a way to cast/project to the Microsoft Display Adapter. As the link states, I do get a "Catastrophic Error" but it does make the connection and keep it, anyway. What my code ended up looking like is below:
static async Task Main()
{
string prefix = "MicrosoftDisplayAdapter";
DeviceInformation displayAdapter = null;
try
{
//Get projection devices
DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(ProjectionManager.GetDeviceSelector());
foreach (DeviceInformation device in devices)
{
if (device.Name.StartsWith(prefix))
{
displayAdapter = device;
}
}
//Start projection. This throws an error but works without issue.
await ProjectionManager.StartProjectingAsync(0, 0, displayAdapter);
}
catch (Exception e)
{
//Ignore this error
if (e.Message.StartsWith("Catastrophic"))
{
//Change display to use secondary only
Process proc = new Process();
proc.StartInfo.UseShellExecute = true;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.FileName = #"C:\Windows\Sysnative\DisplaySwitch.exe";
proc.StartInfo.Arguments = "/external";
proc.Start();
proc.WaitForExit();
}
else
{
Console.WriteLine(e);
}
}
}

Cannot read STDOut from Process that is running in background

So, under Linux I have to connect to a bluetooth device via the command rfcomm connect hci0 xx:xx:xx:xx:xx:xx, which starts a bluetooth connection, but has to remain running in order to stay connected.
I have to write everything as an .NET Core Program
Running the command outputs the following lines after a few seconds:
Connected /dev/rfcomm0 to xx:xx:xx:xx:xx:xx on channel 1
Press CTRL-C for hangup
From that Output I have to get the /dev/rfcomm0 part, so I can read it with a SerialPortReader, and if something goes wrong, like, let's say there is no more data incoming, I have to kill the process and start anew, until I have a good connection.
Now my logic is something like this:
while(!Terminate)
{
string port = Connect();
ReadData(port);
BTProcess.Kill();
}
Don't bother with the ReadData(port); function, as my program never even comes near that.
The Connect() looks something like this:
while (!Connected)
{
Console.WriteLine("Configuring Process");
BTProcess = new Process();
BTProcess.StartInfo.FileName = "rfcomm";
BTProcess.StartInfo.Arguments = "connect hci0 xx:xx:xx:xx:xx:xx"
BTProcess.StartInfo.RedirectStandardOutput = true;
BTProcess.StartInfo.UseShellExecute = false;
Console.WriteLine("Starting Process");
BTProcess.Start();
StreamReader reader = _BTProcess.StandardOutput;
bool done = false;
Console.WriteLine("Reading STDOUT now.");
while (!done) // EDIT: If I do the while with !reader.EndOfStream then it won't even enter into the loop
{
Console.Write("-");
int c = reader.Read(); // Program stops in this line
if(c != -1)
{
port += (char)c;
}
Console.Write(c);
if (c == 0)
{
port = "";
done = true;
_BTProcess.Kill();
}
if (/* String Contains Logic blabla */)
{
port = /* The /dev/rfcomm0 stuff */
Connected = true;
done = true;
}
}
reader.Close();
}
return port;
I did check already if the Output isn't redirected to like STDErr or something, but no, it is 100% written in STDOut.
I have already tried a logic with like an EventHandler that handles StandardOutput Events, and a logic where I read it asynchronously, but both with no success. All had the same problem, they all block at the Read(); function. My guess is that maybe the internal buffer doesn't get flushed correctly.
Maybe someone here knows an answer to my problem.
P.S.: I know my code isn't the best or most optimized, but it should nevertheless work, as I have tried it already with another blocking command under Windows and it worked.
Thanks in advance for every help I get.
I've solved the problem by simply not running the command directly, because that throws buffer problems, so I now don't run the command rfcomm connect hci0 xx:xx:xx:xx:xx:xx, instead I run stdbuf -o0 rfcomm connect hci0 xx:xx:xx:xx:xx:xx, to avoid buffering problems.

Process takes longer to finish than in CMD

I am running a program that runs driverquery.exe command and gets back the ouput
pProcess.StartInfo.CreateNoWindow = true;
debugLog.WriteToLog("");
pProcess.StartInfo.UseShellExecute = false;
pProcess.StartInfo.RedirectStandardOutput = true;
pProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
debugLog.WriteToLog("before start method");
pProcess.Start();
debugLog.WriteToLog("after start method");
if (windowTitleToHide.Length > 0)
{
WindowsUtil.HideWindow(windowTitleToHide);
}
if (null != attributeName && !"".Equals(attributeName))
Console.WriteLine(attributeName + " : ");
debugLog.WriteToLog("before read to end");
StreamReader reader = pProcess.StandardOutput;
String strOutput = string.Empty;
while (reader.Peek() > -1)
strOutput += reader.ReadLine();
debugLog.WriteToLog("after read to end");
Console.WriteLine(strOutput);
debugLog.WriteToLog("before wait for exit");
pProcess.WaitForExit();
debugLog.WriteToLog("after wait for exit");
pProcess.Close();
The process takes about 30 minutes to finish.If i run the same process via cmd it always finishes in 2 minutes. I have tried using readtoend instead of readline but that also did not help. Can some tell what is wrong here? in my logs i can see the last line getting printed as before wait for exit
PS: When i see the processes in the taskmanager the driverquery.exe is running but not consuming any CPU cycles. The process calling this code is consuming about 99% CPU. I know for sure that the calling code is not doing any other task while running this code.
I might guess the problem is related to :
while (reader.Peek() > -1)
strOutput += reader.ReadLine();
You probably are not reading the full output of your application. If there is any pause in its output then reader.Peek() will return -1 before the application is finished its full output. If it is outputting a lot of data you may even be overflowing the output stream since your process will have given up reading after emptying the stream once. If this is the case, the child process may be generating a lot of exceptions outputting to a full stream (which will dramatically increase execution time). Profiling and debugging would tell you more about what is actually going on.
You might try an async approach like this :
pProcess.StartInfo.RedirectStandardOutput = true;
pProcess.EnableRaisingEvents = true; // Enable events
pProcess.OutputDataReceived += outputRedirection; // hook up
pProcess.Start();
pProcess.BeginOutputReadLine(); // use async BeginOutputReadLine
pProcess.WaitForExit();
where
static void outputRedirection(object sendingProcess,
DataReceivedEventArgs outLine)
{
try
{
if (outLine.Data != null)
Console.WriteLine(outLine.Data);
// or collect the data, etc
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
}
Rather than polling in a tight loop (which is likely to empty the output stream faster than the child process will fill it, and therefore fail), this waits for data to come in. Your main process will still block on the call to WaitForExit but a threadpool thread will handle the incoming events.
EDIT
Here is an SSCCE that works just fine :
static void Main(string[] args)
{
Stopwatch spw = new Stopwatch();
spw.Start();
Process pProcess = new Process();
pProcess.StartInfo.FileName = "driverquery.exe";
pProcess.StartInfo.CreateNoWindow = true;
pProcess.StartInfo.UseShellExecute = false;
pProcess.StartInfo.RedirectStandardOutput = true;
pProcess.EnableRaisingEvents = true;
pProcess.OutputDataReceived += outputRedirection;
pProcess.Start();
pProcess.BeginOutputReadLine();
pProcess.WaitForExit();
pProcess.Close();
spw.Stop();
Console.WriteLine();
Console.WriteLine("Completed in : " +
spw.ElapsedMilliseconds.ToString()
+ "ms");
}
Using outputRedirection as define above --> output :
If this isn't working for you, then please show us your complete, real code. Something else you are doing is wrong.

C# program causes bluescreen?

This is only the important stuff that the bluescreen shows. I'm on Windows 7 x64.
"A problem has been detected and Windows has been shut down to prevent damage
to your computer.
PROCESS_HAS_LOCKED_PAGES
* STOP: 0x00000076 (0x0000000000000000, 0xfffffa8009dcd060, 0x0000000000000011,
0x0000000000000000)"
I can't work on it now because every time I close it I get a bluescreen!
The program doesn't do anything yet except run the background worker below. It pings all addresses that could be part of the user's home network and attempts to connect to a certain port that another program will be listening on.
private void NetworkScanner_DoWork(object sender, DoWorkEventArgs e)
{
bool ExceptionEncountered = false;
int IPsProcessed = 0;
NetworkSearcherOutput = "Starting network scanner...";
NetworkSearcher.ReportProgress(0);
Thread.Sleep(1000);
foreach (IPAddress IP in Dns.GetHostAddresses(Dns.GetHostName()))
{
if (IP.AddressFamily == AddressFamily.InterNetwork)
{
string[] Octets = IP.ToString().Split('.');
Octets[3] = "0";
IPAddress CurrentAddressIteration = StringArrayToIP(Octets);
while (GetLastOctet(CurrentAddressIteration) != 255)
{
PingReply Reply = new Ping().Send(CurrentAddressIteration, 5);
if (Reply.Status == IPStatus.Success)
{
NetworkSearcherOutput = CurrentAddressIteration.ToString() + " sent response.";
NetworkSearcher.ReportProgress(0);
Thread.Sleep(500);
InClient Client = new InClient(CurrentAddressIteration);
try
{
Client.Connect();
SnapshotBox.Image = Client.Receive(typeof(Image));
NetworkSearcherOutput = CurrentAddressIteration.ToString() + " is running program.";
NetworkSearcher.ReportProgress(0);
Thread.Sleep(1000);
}
catch (Exception E)
{
// A socket exception is expected when the client is not running the program.
if (E is SocketException)
{
Client.Close();
NetworkSearcherOutput = CurrentAddressIteration.ToString() + " is not running program.";
NetworkSearcher.ReportProgress(0);
Thread.Sleep(1000);
}
//Unhandled exception. Show messagebox and close.
else
{
MessageBox.Show("Network scanner encountered an unhandled exception.\n\n" + E.GetType().ToString() + ": " + E.Message, "Unhandled Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
ExceptionEncountered = true;
break;
}
}
}
else
{
NetworkSearcherOutput = CurrentAddressIteration.ToString() + " did not respond.";
NetworkSearcher.ReportProgress(0);
}
IPsProcessed++;
if (IPsProcessed == 5)
{
NetworkSearcher.ReportProgress(2);
IPsProcessed = 0;
}
Octets = CurrentAddressIteration.ToString().Split('.');
Octets[3] = (Int32.Parse(Octets[3]) + 1).ToString();
CurrentAddressIteration = StringArrayToIP(Octets);
}
}
}
if (!ExceptionEncountered)
{
NetworkSearcherOutput = "Network scanning complete.";
NetworkSearcher.ReportProgress(0);
NetworkSearcher.ReportProgress(100);
}
else
{
NetworkSearcherOutput = "Network scanning encountered an error.";
NetworkSearcher.ReportProgress(-1);
}
I thought C# programs were supposed to never cause bluescreens?
I discovered this issue a few weeks back. It only happens when using .NET 4.
Reported at MS Connect.
Edit:
(Will*) Add this link to MS Connect bug report.
*login.live.com is going into an infinite loop again...
Just to be clear, there is no way for "user" mode code to forcibly create a blue screen in windows, unless it uses undocumented APIs and or forces bad data into a driver. Your C# code is likely not be at fault here, as if you use the user mode classes (Socket) then the socket is responsible for not crashing your computer.
As #Joe has commented Microsoft Support KB Article 256010 clearly describes this stop message, but better yet has clear instructions on capturing the driver name responsible for this error.
Note that any software firewall that you have installed also is involved at kernel mode level so could also be responsible for this error. I recommend you follow the KB articles advice and try to find out what is at fault. But you could also ensure that you have updated your network drivers and firewall/VPN software to the latest stable versions.

Application.Run() operates differently in a Release build w/o a debugger than w/ or in a Debug build

I'm having trouble with a processing thread in C#. Basically the thread manages chat windows when new messages arrive or are sent and unfortunately I'm having different situations occur based on the running environment.
When running a Debug build (either with or without a debugger), or a Release build under a debugger, the Process() function operates correctly, shows windows and receives messages fine.
However, when running a Release build without a debugger, the Application.Run() call seems to stop the processing of the main Process() thread (notice that this call happens under a sub-thread of the processing thread) and so no more processing occurs.
Through the use of the MessageBox.Show() call I have determined that Application.Run() is the last call to be made before no more message boxes are shown (and they should be as it shows how many messages are received each time the while loop runs).
Does anyone know why the Application.Run() call is behaving differently under this situation?
/// <summary>
/// Processes the IM message queue, managing the chat windows and messages.
/// </summary>
private void Process()
{
try
{
MessageBox.Show("MessageQueue process has started!");
while (this.m_Running)
{
List<Message> messages = null;
lock (this.m_Lock)
{
messages = new List<Message>(this.m_Messages);
MessageBox.Show("MessageQueue received " + this.m_Messages.Count + " messages on this spin.");
this.m_Messages.Clear();
}
// Process all the messages
foreach (Message m in messages)
{
Contact c = m.Contact;
if (!this.m_Windows.Keys.Contains(c.ID) || this.m_Windows[c.ID] == null)
{
MessageBox.Show("MessageQueue is creating a new window.");
bool complete = false;
Thread t = new Thread(() =>
{
try
{
ChatWindow w = new ChatWindow(this, c, new Contact(this.m_Client.JID, null));
w.Load += (sender, e) =>
{
if (m.IsTo)
w.AppendSentMessage(m.To, m.Data);
else if (m.IsFrom)
w.AppendRecievedMessage(m.From, m.Data);
w.UpdateStatus(c);
};
w.FormClosed += (sender, e) =>
{
this.m_Windows[c.ID] = null;
};
c.StatusUpdated += (sender, e) =>
{
RoketPack.Manager.VoidLambda lambda = () =>
{
w.UpdateStatus(c);
};
if (w.InvokeRequired)
w.Invoke(lambda);
else
lambda();
};
MessageBox.Show("MessageQueue is now showing the new window.");
w.Show();
if (!this.m_Windows.Keys.Contains(c.ID))
this.m_Windows.Add(c.ID, w);
else
this.m_Windows[c.ID] = w;
complete = true;
MessageBox.Show("MessageQueue is now running the new window.");
Application.Run(w);
MessageBox.Show("MessageQueue is now closing the window.");
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
complete = true;
}
});
t.Name = "IM Chat Window - " + c.ID;
t.IsBackground = true;
t.Start();
// We have to wait until the form has been added to the dictionary.
while (!complete) ;
}
else
{
RoketPack.Manager.VoidLambda lambda = () =>
{
if (m.IsTo)
this.m_Windows[c.ID].AppendSentMessage(m.To, m.Data);
else if (m.IsFrom)
this.m_Windows[c.ID].AppendRecievedMessage(m.From, m.Data);
MessageBox.Show("MessageQueue appended the message to the chat window.");
};
MessageBox.Show("MessageQueue received a message and is now forwarding it onto the chat window.");
if (this.m_Windows[c.ID].InvokeRequired)
this.m_Windows[c.ID].Invoke(lambda);
else
lambda();
}
}
// Sleep for 10 milliseconds.
Thread.Sleep(10);
}
}
finally
{
MessageBox.Show("MessageQueue process has terminated!");
}
}
Aside from what leppie wrote, this looks like a bad starting point:
while (!complete);
I don't know exactly what guarantees there are around hoisted variables and visibility, but tight-looping is almost always a bad idea.
It would generally be better to use a Wait/Notify approach or an Auto/ManualResetEvent.
Do you realize Application.Run does not return until your application closes?
It also seems you are calling Application.Run from a child thread.

Categories

Resources