I'm attempting to create a multi-threaded application which will allow me to ping thousands of hosts, the results of the ping are written to a richtextbox.
After this application executes, once it's iterated through a thousand or so addresses, I'm presented with the following exception:
DisconnectedContext was detected
Message: Transition into COM context 0x4410e0 for this RuntimeCallableWrapper failed with the following error: System call failed. (Exception from HRESULT: 0x80010100 (RPC_E_SYS_CALL_FAILED)). This is typically because the COM context 0x4410e0 where this RuntimeCallableWrapper was created has been disconnected or it is busy doing something else. Releasing the interfaces from the current COM context (COM context 0x440f70). This may cause corruption or data loss. To avoid this problem, please ensure that all COM contexts/apartments/threads stay alive and are available for context transition, until the application is completely done with the RuntimeCallableWrappers that represents COM components that live inside them.
I'm not entirely sure what's causing this, I at first figured it was due to my not disposing Ping but I've since addressed that and the problem still persists.
If anyone has any information on this it would be greatly appreciated.
Thank you all.
public static void LogTextEvent(RichTextBox TextEventLog, Color TextColor, string EventText)
{
if (TextEventLog.InvokeRequired)
{
TextEventLog.BeginInvoke(new Action(delegate { LogTextEvent(TextEventLog, TextColor, EventText); }));
return;
}
string nDateTime = DateTime.Now.ToString("hh:mm:ss tt") + " - ";
// color text.
TextEventLog.SelectionStart = TextEventLog.Text.Length;
TextEventLog.SelectionColor = TextColor;
// newline if first line, append if else.
if (TextEventLog.Lines.Length == 0)
{
TextEventLog.AppendText(nDateTime + EventText);
TextEventLog.ScrollToCaret();
TextEventLog.AppendText(Environment.NewLine);
}
else
{
TextEventLog.AppendText(nDateTime + EventText + Environment.NewLine);
TextEventLog.ScrollToCaret();
}
}
private void button1_Click(object sender, EventArgs e)
{
string[] logFile = File.ReadAllLines("addrs.txt");
var addresses = new List<string>(logFile);
foreach (string ip in addresses)
{
// See http://stackoverflow.com/questions/4744630/unexpected-behaviour-for-threadpool-queueuserworkitem
// for reason to use another variable in the loop
string loopIp = ip;
WaitCallback func = delegate
{
if (PingIP(loopIp))
{
LogTextEvent(richTextBox1, Color.Green, "[ " + loopIp.ToUpper() + " ] - Ping Success");
}
else
{
LogTextEvent(richTextBox1, Color.Red, "[ " + loopIp.ToUpper() + " ] - Ping FAIL!");
}
};
ThreadPool.QueueUserWorkItem(func);
}
}
public static bool PingIP(string IP)
{
bool result = false;
var ping = new Ping();
try
{
//var ping = new Ping();
PingReply pingReply = ping.Send(IP);
if (pingReply.Status == IPStatus.Success)
result = true;
}
catch
{
result = false;
}
finally
{
ping.Dispose();
}
return result;
}
AndyDing is mostly right... problem is with ScrollToCaret... this drove me mad...
I swapped
rtbox.Select(box.Text.Length, 0);
rtbox.ScrollToCaret();
with
rtbox.Focus();
rtbox.Select(rtbox.Text.Length, 0);
problem solved... In my situation swapping RichTextBox for TextBox was not possible... need different colors/alignment bla bla bla... but AndyDing got me on the right path.
Cheers
I encountered the similar "DisconnectedContext" failure, and spent one day to finally figure out the problem is induced by ScrollToCaret() of RichTextBox. I replaced it with a TextBox, which automatically scrolls down, so it even doesn't have a ScrollToCaret() method. Fortunately I don't really need those extra features provided by RichTextBox, a TextBox is just fine in my application. You can give a try.
Related
Below is a button, when pressed it calls a function that pings a bunch of IP addresses. If the IP address returns a response, it adds the IP address to the output_networkSearch.Text.
private void button_networkSearch_Click(object sender, RoutedEventArgs e)
{
output_networkSearch.Text = networkSearch(Convert.ToInt32(input_searchLimit.Text));
}
Below isn't the whole method, just the part that I can't get to work. The for loop starts at whatever the last digit on the users default gateway IP address is, and stops at whatever limit they have inputed (1 - 255).
// i is equal to the last digit in the default gateway IP, if it was 192.168.0.1 then i = 1.
for (int i = Convert.ToInt32(splitGatewayIP[3]); i <= searchLimit; i = i + 1)
{
// If the method receieves a ping reply...
if (PingHostSweep(gatewayIPRebuild + i))
{
// Returns 192.168.0. + i + ACTIVE
string response = gatewayIPRebuild + i + " ACTIVE";
return response;
}
else
{
string response = gatewayIPRebuild + i + " CLOSED";
return response;
}
}
This worked on a console application but for a WPF application it seems to run through the loop once and stop due to the return statement.
My idea to work around this would be to remove the Return Response statements and try and access the TextBox (output_networkSearch) directly.
So I would do something like:
for (int i = Convert.ToInt32(splitGatewayIP[3]); i <= searchLimit; i = i + 1)
{
// If the method receieves a ping reply...
if (PingHostSweep(gatewayIPRebuild + i))
{
// Returns 192.168.0. + i + ACTIVE
string response = gatewayIPRebuild + i + " ACTIVE";
output_networkSearch.Text = reponse;
}
else
{
string response = gatewayIPRebuild + i + " CLOSED";
output_networkSearch.Text = reponse;
}
}
HOWEVER, I can't access the textbox within the method for some reason. I've only just started learning C# so I'm not entirely familiar with how it works.
Here's an image of a partially working concept. As you can see the limit is set at 10, so it should ping IP address 1 through 10 and give an ACTIVE or CLOSED response. This did work in my console application version.
WPF version
Console version
This might do the trick for you
List<string> responses = new List<string>();
string response;
for (int i = Convert.ToInt32(splitGatewayIP[3]); i <= searchLimit; i = i + 1)
{
if (PingHostSweep(gatewayIPRebuild + i))
{
response = gatewayIPRebuild + i + " ACTIVE";
}
else
{
response = gatewayIPRebuild + i + " CLOSED";
}
responses.Add(response)
}
Now after the loop the list which is responses would have the list of all the IPs which are active and closed. Like the way you do had in the console Application.
i think you need use threading, there are need many child threading work in backend to scan, when they finish them work then response the result to MainForm, so i write some code hope can help you!
using System.Threading;
using System.Threading.Tasks;
public void Start(string ip)
{
Task.Factory.StartNew(() =>
{
// If the method receieves a ping reply...
string response;
if (PingHostSweep(ip))
{
// Returns 192.168.0. + i + ACTIVE
response = ip + " ACTIVE";
}
else
{
response = ip + " CLOSED";
}
this.Invoke((MethodInvoker)(() => { textBox1.AppendText("\r\n" + response); }));
});
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 1; i <= 255; i++)
{
Start(String.Format("192.168.100.{0}", i));
}
}
The previous answer was correct (though it didn't touch on a more advanced point that you will ultimately need to learn ... delegation and invocation ... long story ... won't bore you now).
What you wrote distills to this:
// SIDE NOTE: you cannot actually treat an IPv4 address as four "pure" quads (but that's not your question)
var notNecessarilyAHost = splitGatewayIP[3];
var searchStart = Convert.ToInt32(notNecessarilyAHost);
for (var i = searchStart; i <= searchLimit; ++i)
{
if (PingHostSweep(gatewayIPRebuild + i))
{
return $"{gatewayIPRebuild}{i} ACTIVE";
}
else
{
return $"{gatewayIPRebuild}{i} CLOSED";
}
}
...and if you (mentally) step through what you wrote it's fairly straightforward to see that the loop will only ever cycle once. Upon entry to the loop i will be equal to whatever searchStart is. Then you enter the if test. If that test is true, you fall into the true side of the branch (i.e., "...ACTIVE"). Otherwise, you'll drop into the else branch (i.e., "...CLOSED". FROM THERE...
You ALWAYS return. That will exit the loop (and the function that contains it). You will never cycle the loop again. "break" and "return" (and plausibly goto ... but that's for a different day) will ALWAYS exit the current scope (scope being a block of code wrapped by '{' and '}' (be they explicitly or implicitly written).
Following?
The previous answer was correct. It adjusts your code so that the loop adds the string you're composing with each iteration to a list of strings. Then, when you exit the loop (because i reaches searchLimit) that list of strings will contain N many, well, strings. You probably want to return or continue working that.
All that said, you can't (technically you can but you SHOULDN'T) do any of this inside a UI thread. If you do, the UI will block (and become 100% unresponsive to the user) while the loop runs (and the network calls that it makes run), etc.
When using Ping in correlation with PingReply to check the status of an IP Address and it's ports for and imported text list how do you launch a code to skip the current one and move onto the next one?
PingReply reply = ping.Send("IP", "PORT");
Specifically
PingReply reply = ping.Send("174.69.75.251", "41968");
There is no response at all, it just freezes the application so you cant check the reply status if its successful.
Going to a list of proxies I want to check if they're valid and able to be connected to a webBrowser1 control so I have the following code to send the request for the IP Address and Port to check if it will accept connections.
This is the whole code for the loop and everything, I have added what has been suggested by two people and excluded the TCPClient one with /* */ heres the code for the button:
private void button2_Click(object sender, EventArgs e)
{
numberProx = Convert.ToInt32(textBox1.Lines.Length.ToString());
proxyList = textBox1.Text.Split(new Char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
while (i < numberProx)
{
string currentProxy = proxyList[i++].ToString();
try
{/*
TcpClient reply2 = new TcpClient();
reply2.ConnectAsync(currentProxy.Split(':')[0],
Convert.ToInt32(currentProxy.Split(':')[1]));
if (reply2.Connected)
{
textBox2.AppendText(currentProxy + "\n");
}
else
{
textBox3.AppendText(currentProxy + "\n");
}*/
//PingReply reply = proxy.Send(currentProxy.Split(':')[0], Convert.ToInt32(currentProxy.Split(':')[1]));
PingReply reply = await proxy.SendPingAsync("174.69.75.251", 5000);
if (reply.Status == IPStatus.Success)
{
textBox2.AppendText(currentProxy + "\n");
}
else if (reply.Status == IPStatus.TimedOut)
{
}
else if (reply.RoundtripTime >= 5000)
{
textBox3.AppendText(currentProxy + "\n");
}
else
{
textBox3.AppendText(currentProxy + "\n");
}
}
catch (PingException ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
}
That is everything including the loop and incremented integer to match the number of proxies in the string[] called proxyList.
What I want to do is see if the proxy is capable of working in a webBrowser control without the form/UI freezing.
A ping request can't test an applicative PORT. For this, you have telnet.
The parameters taken by 'ping.Send' are:
ping.Send('IP_ADDRESS', 'TIMEOUT');
Like it is said in the MSDN Documentation
You could specify a timeout using the overload of Ping.Send that accepts one. This takes the number of milliseconds to wait before timing out.
If you are in a UI application and this is causing your UI thread to freeze you could use the asynchronous method and await the result. This would allow your UI to remain responsive while the request is being sent.
using IPC over local TCP to communicate from Client to a Server thread. The connection itself doesn't seem to be throwing any errors, but every time I try to make one of the associated calls, I get this message:
System.Runtime.Remoting.RemotingException: Could not connect to an IPC Port: The System cannot Find the file specified
What I am attempting to figure out is WHY. Because this WAS working correctly, until I transitioned the projects in question (yes, both) from .NET 3.5 to .NET 4.0.
Listen Code
private void ThreadListen()
{
_listenerThread = new Thread(Listen) {Name = "Listener Thread", Priority = ThreadPriority.AboveNormal};
_listenerThread.Start();
}
private void Listen()
{
_listener = new Listener(this);
LifetimeServices.LeaseTime = TimeSpan.FromDays(365);
IDictionary props = new Hashtable();
props["port"] = 63726;
props["name"] = "AGENT";
TcpChannel channel = new TcpChannel(props, null, null);
ChannelServices.RegisterChannel(channel, false);
RemotingServices.Marshal(_listener, "Agent");
Logger.WriteLog(new LogMessage(MethodBase.GetCurrentMethod().Name, "Now Listening for commands..."));
LogEvent("Now Listening for commands...");
}
Selected Client Code
private void InitializeAgent()
{
try
{
_agentController =
(IAgent)RemotingServices.Connect(typeof(IAgent), IPC_URL);
//Note: IPC_URL was originally "ipc://AGENT/AGENT"
// It has been changed to read "tcp://localhost:63726/Agent"
SetAgentPid();
}
catch (Exception ex)
{
HandleError("Unable to initialize the connected agent.", 3850244, ex);
}
}
//This is the method that throws the error
public override void LoadTimer()
{
// first check to see if we have already set the agent process id and set it if not
if (_agentPid < 0)
{
SetAgentPid();
}
try
{
TryStart();
var tries = 0;
while (tries < RUNCHECK_TRYCOUNT)
{
try
{
_agentController.ReloadSettings();//<---Error occurs here
return;
} catch (RemotingException)
{
Thread.Sleep(2000);
tries++;
if (tries == RUNCHECK_TRYCOUNT)
throw;
}
}
}
catch (Exception ex)
{
HandleError("Unable to reload the timer for the connected agent.", 3850243, ex);
}
}
If you need to see something I haven't shown, please ask, I'm pretty much flying blind here.
Edit: I think the issue is the IPC_URL String. It is currently set to "ipc://AGENT/AGENT". The thing is, I have no idea where that came from, why it worked before, or what might be stopping it from working now.
Update
I was able to get the IPC Calls working correctly by changing the IPC_URL String, but I still lack understanding of why what I did worked. Or rather, why the original code stopped working and I needed to change it in the first place.
The string I am using now is "tcp://localhost:63726/Agent"
Can anyone tell me, not why the new string works, I know that...but Why did the original string work before and why did updating the project target to .NET 4.0 break it?
In C# ASP.NET 3.5 web application running on Windows Server 2003, I get the following error once in a while:
"Object reference not set to an instance of an object.: at System.Messaging.Interop.MessagePropertyVariants.Unlock()
at System.Messaging.Message.Unlock()
at System.Messaging.MessageQueue.ReceiveCurrent(TimeSpan timeout, Int32 action, CursorHandle cursor, MessagePropertyFilter filter, MessageQueueTransaction internalTransaction, MessageQueueTransactionType transactionType)
at System.Messaging.MessageEnumerator.get_Current()
at System.Messaging.MessageQueue.GetAllMessages()".
The line of code that throws this error is:
Message[] msgs = Global.getOutputQueue(mode).GetAllMessages();
where Global.getOutputQueue(mode) gives the messagequeue I want to get messages from.
Update:
Global.getPool(mode).WaitOne();
commonClass.log(-1, "Acquired pool: " + mode, "Report ID: " + unique_report_id);
............../* some code /
..............
lock(getLock(mode))
{
bool yet_to_get = true;
int num_retry = 0;
do
{
try
{
msgs = Global.getOutputQueue(mode).GetAllMessages();
yet_to_get = false;
}
catch
{
Global.setOutputQueue(mode);
msgs = Global.getOutputQueue(mode).GetAllMessages();
yet_to_get = false;
}
++num_retry;
}
while (yet_to_get && num_retry < 2);
}
... / some code*/
....
finally
{
commonClass.log(-1, "Released pool: " + mode, "Report ID: " + unique_report_id);
Global.getPool(mode).Release();
}
Your description and this thread suggests a timing issue. I would create the MessageQueue object infrequently (maybe only once) and have Global.getOutputQueue(mode) return a cached version, seems likely to get around this.
EDIT: Further details suggest you have the opposite problem. I suggest encapsulating access to the message queue, catching this exception and recreating the queue if that exception occurs. So, replace the call to Global.getOutputQueue(mode).GetAllMessages() with something like this:
public void getAllOutputQueueMessages()
{
try
{
return queue_.GetAllMessages();
}
catch (Exception)
{
queue_ = OpenQueue();
return queue_.GetAllMessages();
}
}
You'll notice I did not preserve your mode functionality, but you get the idea. Of course, you have to duplicate this pattern for other calls you make to the queue, but only for the ones you make (not the whole queue interface).
This is an old thread, but google brought me here so I shall add my findings.
I agree with user: tallseth that this is a timing issue.
After the message queue is created it is not instantly available.
try
{
return _queue.GetAllMessages().Length;
}
catch (Exception)
{
System.Threading.Thread.Sleep(4000);
return _queue.GetAllMessages().Length;
}
try adding a pause if you catch an exception when accessing a queue which you know has been created.
On a related note
_logQueuePath = logQueuePath.StartsWith(#".\") ? logQueuePath : #".\" + logQueuePath;
_queue = new MessageQueue(_logQueuePath);
MessageQueue.Create(_logQueuePath);
bool exists = MessageQueue.Exists(_logQueuePath);
running the MessageQueue.Exists(string nameofQ); method immediately after creating the queue will return false. So be careful when calling code such as:
public void CreateQueue()
{
if (!MessageQueue.Exists(_logQueuePath))
{
MessageQueue.Create(_logQueuePath);
}
}
As it is likely to throw an exception stating that the queue you are trying to create already exists.
-edit: (Sorry I don't have the relevant link for this new info)
I read that a newly created MessageQueue will return false on MessageQueue.Exists(QueuePath)until it has received at least one message.
Keeping this and the earlier points i mentioned in mind has gotten my code running reliably.
I guess you all misunderstood my question and closed it at How to run a Command in C# and retrieve data from it?
I had said in that post also :-
want to run a Command from command promt and want its output and maipulate its output. If required, want to close the process and display error or appropriate message. To stop the process, I have to press "F4' key on command prompt. Till the process is stopeed or killed, it has to be alive only.
I have created a class to handle running the cmd. And I keep getting the output. But on reading the output's each line I want to stop or throw exception if found anything improper in the output.
I am tying to connect to server via cmd. Server keeps on giving output. Suppose the server gave output as :
Trying to start .....
Cananot load file
.....
Exiting
While retrieving the output, I want to check for lines like "Cannot find file", "Connected Successfully, etc and set properties ccordingly (like connected = true, errorMsg = "Cannot find file". Where I am calling the class, I can take care of those proeprties and stop if found connected == true or errorMsg.length > 0. With this inform the user that "Connection is achieved or error msg stating regarding "Cannot load file" and disconnect the server if errorMsg found.
I didn't find anywhere doing any manipulation on the output receving and that's where I find myself stuck. I found a lot on internet. Am stuck and trying to figre out this part from last 3-4 days. Then have posted here.
I need help in that. Please help me. If requiried I will psot code snippets. But please help me. AND don't close this thread as answered ithout understanding my question fully. This is no duplicate.
My code is class :
public int ConnectToServer()
{
int error = 0;
connected = false;
try
{
process = Process.Start(processInfo);
process.BeginOutputReadLine();
process.OutputDataReceived += new DataReceivedEventHandler(Process_OutputDataReceived);
//if (errorMsg.Length > 0)
// throw new Exception(errorMsg);
}
catch (Exception e)
{
Console.WriteLine("Error Processing ConnectToServer : " + e.Message);
connected = false;
errorMsg = e.Message;
error = -1;
return error;
}
return error;
}
private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
errorMsg = "";
connected = false;
string d = e.Data;
if (!string.IsNullOrEmpty(d))
{
if (sb != null)
sb.Append(d + "\n");
Console.WriteLine("LINE = " + d);
if (d.IndexOf("Initialization Completed") > 0)
{
connected = true;
Console.WriteLine("********* Connected = " + connected);
}
else if (isInValidLine(d))
{
//throw new Exception(d);
connected = false;
errorMsg = d;
return;
}
}
return;
}
private bool isInValidLine(string line)
{
if (line.IndexOf("Cannot load file") > 0)
{
errorMsg = line;
return true;
}
return false;
}
IS THE ABOVE CLASS CODE CORRECT WITH MY REQUIREMENTS ?
In impementation :
while (!oc.Connected)
{
timepassed = (int)(DateTime.Now - start).TotalMilliseconds;
if (timepassed > timeout)
{
oc.DisconnectServer();
connectedToVpn = false;
throw new Exception("NotConnectedException");
} else if (oc.ErrorMessage.Length > 0)
{
oc.DisconnectServer();
connectedToVpn = false;
throw new Exception(oc.ErrorMessage);
}
Thread.Sleep(100);
}
Here what I am doing is, when I get the output line, I check if it states as Conneced or is invalid. If its invalid, I set the line as the errorMsg. In my while loop I keep chekcing for Connected and errorMessage, but the value of errorMessage stays as "" only. It never gets updated, which tell me that the processing output code is never executed. Nor in debug mode I find the cursor at that line, but the Line = is displayed proeprly in Console. So, don't understand what's going wrong and where.
Hope this helps you more understand.
Thanks
once you have redirected the standard output of the process you have executed you could parse what you receive as it arrives, I believe also line by line, then you can post commands to control your process.
to read output you have redirected the standard output, to send input you should also redirect the standard input of the process.