How to catch a Lua exception in C# - c#

I am using the an assembly named LuaInterface to run lua-code inside my C# application. During the lua execution I create some WinForms & map event handlers (lua-methods) to them.
The problem is that the doString (aka runLuaCode) method only runs the init routine and the constructors. This is fine and intended, however the doString function acts non blocking so the function returns while the Lua-created-Forms are still there. This means that any exception (null-ref and alike) which is not raised during the constructor is not handled by the lua error handling an crashes all the way up to my wndProc of my Editor - which most likely kills my editor and make error handling virtually impossible.
Is there any way to create a new Thread / Process / AppDomain that handles it's own WndProc so that only this sub-task needs to handle the exceptions?
Should I block my Editor at the doString with a while loop in lua until the forms are closed?
What other options do I have?
Any advice on this matter is greatly appreciated!

Another Lua enthusiast!! Finally! :) I am also toying with the idea to use Lua for macro scripting in my .NET apps.
I am not sure I get it. I wrote some sample code and it seems to be working ok. Simple try catch around DoString gets the LuaExceptions. DoString does block the main thread unless you explicitly create a new thread. In case of a new thread normal .NET multithreaded exception handling rules apply.
Example:
public const string ScriptTxt = #"
luanet.load_assembly ""System.Windows.Forms""
luanet.load_assembly ""System.Drawing""
Form = luanet.import_type ""System.Windows.Forms.Form""
Button = luanet.import_type ""System.Windows.Forms.Button""
Point = luanet.import_type ""System.Drawing.Point""
MessageBox = luanet.import_type ""System.Windows.Forms.MessageBox""
MessageBoxButtons = luanet.import_type ""System.Windows.Forms.MessageBoxButtons""
form = Form()
form.Text = ""Hello, World!""
button = Button()
button.Text = ""Click Me!""
button.Location = Point(20,20)
button.Click:Add(function()
MessageBox:Show(""Clicked!"", """", MessageBoxButtons.OK) -- this will throw an ex
end)
form.Controls:Add(button)
form:ShowDialog()";
private static void Main(string[] args)
{
try
{
var lua = new Lua();
lua.DoString(ScriptTxt);
}
catch(LuaException ex)
{
Console.WriteLine(ex.Message);
}
catch(Exception ex)
{
if (ex.Source == "LuaInterface")
{
Console.WriteLine(ex.Message);
}
else
{
throw;
}
}
Console.ReadLine();
}
LuaInterface has a pretty good documentation where tricky error handling is explained.
http://penlight.luaforge.net/packages/LuaInterface/#T6
I hope it helps. :)

Related

How to re-start a console application if it crashes?

I have created a console application in C#. How can I program this application so that it will re-start itself after a crash?
If I understand your question correctly, you want to attempt to re-start a console app in the event of a crash. In C# console-apps the method defined as the entry point (usually static void main) is the root of the call stacks in the app. You essentially would need to call that method recursively. You will want to make sure that the app eventually fails if it is in some unintended or unrecoverable state.
For example in the main class:
static int retryCount;
const int numberOfRetries = 3;
static void Main(string[] args)
{
try
{
var theApp = new MyApplicationType(args);
theApp.StartMyAppLogic();
}
catch (ExpectedExceptionType expectThisTypeOfException)
{
thisMethodHandlesExceptions(expectThisTypeOfException);
}
catch (AnotherExpectedExceptionType alsoExpectThisTypeOfException)
{
thisMethodHandlesExceptions(alsoExpectThisTypeOfException);
}
catch (Exception unexpectedException)
{
if(retryCount < numberOfRetries)
{
retryCount++;
Main(args);
}
else
{
throw;
}
}
}
You can use a watchdog to process your monitor and restart it if crashed:
see: What's the best way to watchdog a desktop application?
You can use a windows service instead and set it's recovery options as indicated here: https://serverfault.com/questions/48600/how-can-i-automatically-restart-a-windows-service-if-it-crashes
You can use a scheduled task in task manager to start your application periodically , and set it to only start if previous run has ended:
https://support.microsoft.com/en-us/kb/323527
You could try something like this:
static void Main(string[] args)
{
try
{
// Application code goes here
}
catch (Exception)
{
var applicationPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
Process.Start(applicationPath);
Environment.Exit(Environment.ExitCode);
}
}
Basically, wrap all the code in a try/catch, and if any exceptions occur, the program will retrieve the .exe location with System.Reflection.Assembly.GetExecutingAssembly().Location; and then call Process.Start to run the application again.
You should control your console app from another application (watchdog, sheduler, procmon, servman, ...).
E.g. you can create your console app as a service and control it from service manager.

How to report custom error strings from child process while preserving debugger functionality

I have a program that creates a subprocess and trys to handle any error messages as per below:
study.StartInfo.FileName = studyWorkingDir +"\\"+ clargParts[0];
study.StartInfo.Arguments = clargs;
study.StartInfo.UseShellExecute = false;
study.StartInfo.RedirectStandardError = true;
study.ErrorDataReceived += (sender, args) =>
{
Process process = (Process)sender;
if (!process.HasExited)
{
MyErrorBroadcaster.BroadcastMessage("Instance error: " + args.Data.ToString());
process.kill();
}
};
study.Start(); // Start the Study!
study.PriorityClass = ProcessPriorityClass.BelowNormal;
study.BeginErrorReadLine();
The child process is an application (given below). In order to actually get a non-empty error in the above master process, I've needed to wrap the whole sub-program in a try-catch which makes a custom Console.Error.WriteLine() call
static class Program
{
static void Main()
{
try
{
Console.Title = "MyProgram";
Application.Run(new GUI());
}
catch (Exception e)
{
Console.Error.WriteLine(e.ToString().Replace("\r\n","\t"));
}
}
}
The problem is, this try-catch in the child program clobbers the debugger from stopping on the actual error locations in visual studio, which I think will annoy/be problematic for me and my coworkers as we develop. (Seems kludgy too!)
Is there a better way to get have this sub-application to report errors to the master process, without affecting normal debugger operation?
Revisiting this, the problem was that the master process was only getting the errors one line at a time and that first line happened to be "", after which it immediately closes the process (ignoring the following error lines). The e.ToString().Replace("\r\n","\t") bypassed this issue by guaranteeing the error was one line, but with unwanted side effects.
A better solution for me was the following:
study.StartInfo.UseShellExecute = false;
study.StartInfo.RedirectStandardError = true;
study.Start(); // Start the Study!
//This thread collects errors until the process ends, then reports them
(new Thread(() =>
{
//Acumulate errors, then send
String err = study.StandardError.ReadToEnd();
if (!string.IsNullOrEmpty(err))
MyErrorBroadcaster.BroadcastMessage("Instance Error", "\tInstance error: " + err);
})).Start();
This approach uses the study.StandardError.ReadToEnd(). This command is blocking which would be unsuitable for my purposes, so It is in a lambda thread (so the main program can move on!)

Delegate.BeginInvoke doesn't appear to do anything on a different PC

private void button1_Click(object sender, EventArgs e)
{
this.icon_testLOAD.Visible = true;
this.icon_testOK.Visible = false;
this.icon_testBAD.Visible = false;
this.debug("Test Service Button Clicked");
rabbitmq_test t = new rabbitmq_test(button_rabbitmq_test);
this.debug("Calling BeginInvoke on button_rabbitmq_test delegate");
t.BeginInvoke(null, null);
}
So I have this button click event. The first three lines are turning on and off PictureBoxes that contain icons.
this.debug() merely calls EventLog.WriteEntry()
The button_rabbitmq_test method looks like:
protected void button_rabbitmq_test()
{
this.debug("Creating new rabbitmq connection factory");
IConnection connection;
try
{
ConnectionFactory rq_factory = new ConnectionFactory();
rq_factory.Port = Convert.ToInt16(this.psistats_config.rabbitmq_port);
rq_factory.HostName = this.psistats_config.rabbitmq_server;
rq_factory.UserName = this.psistats_config.rabbitmq_username;
rq_factory.Password = this.psistats_config.rabbitmq_password;
rq_factory.RequestedConnectionTimeout = 15000;
this.debug("Creating new rabbitmq connection");
connection = rq_factory.CreateConnection();
this.debug("Changing icon to successful");
rabbitmq_icon_delegate d = new rabbitmq_icon_delegate(this.testOK);
connection.Close();
this.test_button.Invoke(d);
}
catch (Exception exc)
{
if (connection != null)
{
connection.Close();
}
this.debug("Failed testing the rabbit server");
this.debug(exc.Message);
this.debug(exc.StackTrace);
rabbitmq_icon_delegate d = new rabbitmq_icon_delegate(this.testFailed);
this.test_button.Invoke(d);
}
}
This code works fine on the computer I'm doing the development on. The method executes, the event log is populated as expected. However, when I run this application on a second machine, the BeginInvoke method doesn't seem to do anything at all and I have absolutely no idea why.
The last message I see in the event log is "Calling BeginInvoke..." but the event logs from the method that performs the actual test are not seen anywhere.
The application is also not frozen. I can still use it.
I am at a loss as to what I am doing wrong and any advice would be welcome.
The code is fundamentally flawed, you must call the delegate's EndInvoke() method. Best done by not passing null as the first argument, use a callback method that then calls EndInvoke().
If you don't call EndInvoke() then you'll leak resources, lasts for 10 minutes. And the ultimate problem you are asking about, you can't see an exception that was raised by the method. So you cannot find out why it didn't work. Calling EndInvoke() rethrows that exception.
Using a delegate's BeginInvoke() method is a low-level programming technique that's best avoided, too easy to make mistakes like this and too difficult to deal with exceptions. Use a BackgroundWorker or a Task instead.

Variable mysteriously changing value

EDIT: Ok I had a problem with one of the string concatenation functions, has nothing to do with threads, but knowing that it couldn't be a problem with threading lead me to the answer thank you for answering.
I am making a simple tcp/ip chat program for practicing threads and tcp/ip. I was using asynchronous methods but had a problem with concurrency so I went to threads and blocking methods (not asynchronous). I have two private variables defined in the class, not static:
string amessage = string.Empty;
int MessageLength;
and a Thread
private Thread BeginRead;
Ok so I call a function called Listen ONCE when the client starts:
public virtual void Listen(int byteLength)
{
var state = new StateObject {Buffer = new byte[byteLength]};
BeginRead = new Thread(ReadThread);
BeginRead.Start(state);
}
and finally the function to receive commands and process them, I'm going to shorten it because it is really long:
private void ReadThread(object objectState)
{
var state = (StateObject)objectState;
int byteLength = state.Buffer.Length;
while (true)
{
var buffer = new byte[byteLength];
int len = MySocket.Receive(buffer);
if (len <= 0) return;
string content = Encoding.ASCII.GetString(buffer, 0, len);
amessage += cleanMessage.Substring(0, MessageLength);
if (OnRead != null)
{
var e = new CommandEventArgs(amessage);
OnRead(this, e);
}
}
}
Now, as I understand it only one thread at a time will enter BeginRead, I call Receive, it blocks until I get data, and then I process it. The problem: the variable amessage will change it's value between statements that do not touch or alter the variable at all, for example at the bottom of the function at: if (OnRead != null) "amessage" will be equal to 'asdf' and at if (OnRead != null) "amessage" will be equal to qwert. As I understand it this is indicative of another thread changing the value/running asynchronously. I only spawn one thread to do the receiving and the Receive function is blocking, how could there be two threads in this function and if there is only one thread how does amessage's value change between statements that don't affect it's value. As a side note sorry for spamming the site with these questions but I'm just getting a hang of this threading story and it's making me want to sip cyanide.
Thanks in advance.
EDIT:
Here is my code that calls the Listen Method in the client:
public void ConnectClient(string ip,int port)
{
client.Connect(ip,port);
client.Listen(5);
}
and in the server:
private void Accept(IAsyncResult result)
{
var client = new AbstractClient(MySocket.EndAccept(result));
var e = new CommandEventArgs(client, null);
Clients.Add(client);
client.Listen(5);
if (OnClientAdded != null)
{
var target = (Control) OnClientAdded.Target;
if (target != null && target.InvokeRequired)
target.Invoke(OnClientAdded, this, e);
else
OnClientAdded(this, e);
}
client.OnRead += OnRead;
MySocket.BeginAccept(new AsyncCallback(Accept), null);
}
All this code is in a class called AbstractClient. The client inherits the Abstract client and when the server accepts a socket it create's it's own local AbstractClient, in this case both modules access the functions above however they are different instances and I couldn't imagine threads from different instances combining especially as no variable is static.
Well, this makes no sense the way you described it. Which probably means that what you think is going on is not what is really happening. Debugging threaded code is quite difficult, very hard to capture the state of the program at the exact moment it misbehaves.
A generic approach is to add logging to your code. Sprinkle your code with Debug.WriteLine() statements that shows the current value of the variable, along with the thread's ManagedId. You get potentially a lot of output, but somewhere you'll see it going wrong. Or you get enough insight in how thread(s) are interacting to guess the source of the problem.
Just adding the logging can in itself solve the problem because it alters the timing of code. Sucks when that happens.
I assume OnRead is firing an event dispatched on a thread pool thread. If any registered event handler is writing to amessage, its value could change any time you're in the reading loop.
Still not very clear where you are gettingthe value assigned to amessage in the loop. Should cleanmessage read content?

How do I programmatically use the "using" keyword in C#?

I have some System.Diagnotics.Processes to run. I'd like to call the close method on them automatically. Apparently the "using" keyword does this for me.
Is this the way to use the using keyword?
foreach(string command in S) // command is something like "c:\a.exe"
{
try
{
using(p = Process.Start(command))
{
// I literally put nothing in here.
}
}
catch (Exception e)
{
// notify of process failure
}
}
I'd like to start multiple processes to run concurrently.
using(p = Process.Start(command))
This will compile, as the Process class implements IDisposable, however you actually want to call the Close method.
Logic would have it that the Dispose method would call Close for you, and by digging into the CLR using reflector, we can see that it does in fact do this for us. So far so good.
Again using reflector, I looked at what the Close method does - it releases the underlying native win32 process handle, and clears some member variables. This (releasing external resources) is exactly what the IDisposable pattern is supposed to do.
However I'm not sure if this is what you want to achieve here.
Releasing the underlying handles simply says to windows 'I am no longer interested in tracking this other process'. At no point does it actually cause the other process to quit, or cause your process to wait.
If you want to force them quit, you'll need to use the p.Kill() method on the processes - however be advised it is never a good idea to kill processes as they can't clean up after themselves, and may leave behind corrupt files, and so on.
If you want to wait for them to quit on their own, you could use p.WaitForExit() - however this will only work if you're waiting for one process at a time. If you want to wait for them all concurrently, it gets tricky.
Normally you'd use WaitHandle.WaitAll for this, but as there's no way to get a WaitHandle object out of a System.Diagnostics.Process, you can't do this (seriously, wtf were microsoft thinking?).
You could spin up a thread for each process, and call `WaitForExit in those threads, but this is also the wrong way to do it.
You instead have to use p/invoke to access the native win32 WaitForMultipleObjects function.
Here's a sample (which I've tested, and actually works)
[System.Runtime.InteropServices.DllImport( "kernel32.dll" )]
static extern uint WaitForMultipleObjects( uint nCount, IntPtr[] lpHandles, bool bWaitAll, uint dwMilliseconds );
static void Main( string[] args )
{
var procs = new Process[] {
Process.Start( #"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 2'" ),
Process.Start( #"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 3'" ),
Process.Start( #"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 4'" ) };
// all started asynchronously in the background
var handles = procs.Select( p => p.Handle ).ToArray();
WaitForMultipleObjects( (uint)handles.Length, handles, true, uint.MaxValue ); // uint.maxvalue waits forever
}
For reference:
The using keyword for IDisposable objects:
using(Writer writer = new Writer())
{
writer.Write("Hello");
}
is just compiler syntax. What it compiles down to is:
Writer writer = null;
try
{
writer = new Writer();
writer.Write("Hello");
}
finally
{
if( writer != null)
{
((IDisposable)writer).Dispose();
}
}
using is a bit better since the compiler prevents you from reassigning the writer reference inside the using block.
The framework guidelines Section 9.3.1 p. 256 state:
CONSIDER providing method Close(), in addition to the Dispose(), if close is standard terminology in the area.
In your code example, the outer try-catch is unnecessary (see above).
Using probably isn't doing what you want to here since Dispose() gets called as soon as p goes out of scope. This doesn't shut down the process (tested).
Processes are independent, so unless you call p.WaitForExit() they spin off and do their own thing completely independent of your program.
Counter-intuitively, for a Process, Close() only releases resources but leaves the program running. CloseMainWindow() can work for some processes, and Kill() will work to kill any process. Both CloseMainWindow() and Kill() can throw exceptions, so be careful if you're using them in a finally block.
To finish, here's some code that waits for processes to finish but doesn't kill off the processes when an exception occurs. I'm not saying it's better than Orion Edwards, just different.
List<System.Diagnostics.Process> processList = new List<System.Diagnostics.Process>();
try
{
foreach (string command in Commands)
{
processList.Add(System.Diagnostics.Process.Start(command));
}
// loop until all spawned processes Exit normally.
while (processList.Any())
{
System.Threading.Thread.Sleep(1000); // wait and see.
List<System.Diagnostics.Process> finished = (from o in processList
where o.HasExited
select o).ToList();
processList = processList.Except(finished).ToList();
foreach (var p in finished)
{
// could inspect exit code and exit time.
// note many properties are unavailable after process exits
p.Close();
}
}
}
catch (Exception ex)
{
// log the exception
throw;
}
finally
{
foreach (var p in processList)
{
if (p != null)
{
//if (!p.HasExited)
// processes will still be running
// but CloseMainWindow() or Kill() can throw exceptions
p.Dispose();
}
}
}
I didn't bother Kill()'ing off the processes because the code starts get even uglier. Read the msdn documentation for more information.
try
{
foreach(string command in S) // command is something like "c:\a.exe"
{
using(p = Process.Start(command))
{
// I literally put nothing in here.
}
}
}
catch (Exception e)
{
// notify of process failure
}
The reason it works is because when the exception happens, the variable p falls out of scope and thus it's Dispose method is called that closes the process is how that would go. Additionally, I would think you'd want to spin a thread off for each command rather than wait for an executable to finish before going on to the next one.

Categories