I started coding a simple game in Windows Form C#, but after I added the background sound (a simple .wav file) when I run the game, after a few second of playing the game crashes. (The sound can be heard).
Here is the function:
private void playAmbientSound()
{
System.Media.SoundPlayer playAmbient = new System.Media.SoundPlayer(Properties.Resources.ambient);
playAmbient.PlayLooping();
}
Then I call this function from the function resetGame() a function used in the Form constructor.
public Form1()
{
InitializeComponent();
resetGame();
}
The code that appears in the console after the crash is:
.. has exited with code -1073741819 (0xc0000005) 'Access Violation'".
As requested here is the resetGame() function:
private void resetGame()
{
btnStart.Enabled = false;
explosion.Visible = false;
award.Visible = false;
goLeft = false;
goRight = false;
score = 0;
award.Image = Properties.Resources.bronze;
roadSpeed = 12;
trafficSpeed = 15;
AI1.Top = carPosition.Next(200, 500) * -1;
AI1.Left = carPosition.Next(5, 200);
AI2.Top = carPosition.Next(200, 500) * -1;
AI2.Left = carPosition.Next(245, 422);
playAmbientSound();
gameTimer.Start();
}
I have a console application that contains quite a lot of threads. There are threads that monitor certain conditions and terminate the program if they are true. This termination can happen at any time.
I need an event that can be triggered when the program is closing so that I can cleanup all of the other threads and close all file handles and connections properly. I'm not sure if there is one already built into the .NET framework, so I'm asking before I write my own.
I was wondering if there was an event along the lines of:
MyConsoleProgram.OnExit += CleanupBeforeExit;
I am not sure where I found the code on the web, but I found it now in one of my old projects. This will allow you to do cleanup code in your console, e.g. when it is abruptly closed or due to a shutdown...
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
private delegate bool EventHandler(CtrlType sig);
static EventHandler _handler;
enum CtrlType
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}
private static bool Handler(CtrlType sig)
{
switch (sig)
{
case CtrlType.CTRL_C_EVENT:
case CtrlType.CTRL_LOGOFF_EVENT:
case CtrlType.CTRL_SHUTDOWN_EVENT:
case CtrlType.CTRL_CLOSE_EVENT:
default:
return false;
}
}
static void Main(string[] args)
{
// Some biolerplate to react to close window event
_handler += new EventHandler(Handler);
SetConsoleCtrlHandler(_handler, true);
...
}
Update
For those not checking the comments it seems that this particular solution does not work well (or at all) on Windows 7. The following thread talks about this
Full working example, works with ctrl-c, closing the windows with X and kill:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace TestTrapCtrlC {
public class Program {
static bool exitSystem = false;
#region Trap application termination
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
private delegate bool EventHandler(CtrlType sig);
static EventHandler _handler;
enum CtrlType {
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}
private static bool Handler(CtrlType sig) {
Console.WriteLine("Exiting system due to external CTRL-C, or process kill, or shutdown");
//do your cleanup here
Thread.Sleep(5000); //simulate some cleanup delay
Console.WriteLine("Cleanup complete");
//allow main to run off
exitSystem = true;
//shutdown right away so there are no lingering threads
Environment.Exit(-1);
return true;
}
#endregion
static void Main(string[] args) {
// Some boilerplate to react to close window event, CTRL-C, kill, etc
_handler += new EventHandler(Handler);
SetConsoleCtrlHandler(_handler, true);
//start your multi threaded program here
Program p = new Program();
p.Start();
//hold the console so it doesn’t run off the end
while (!exitSystem) {
Thread.Sleep(500);
}
}
public void Start() {
// start a thread and start doing some processing
Console.WriteLine("Thread started, processing..");
}
}
}
Check also:
AppDomain.CurrentDomain.ProcessExit
I've had a similar problem, just my console App would be running in infinite loop with one preemptive statement on middle. Here is my solution:
class Program
{
static int Main(string[] args)
{
// Init Code...
Console.CancelKeyPress += Console_CancelKeyPress; // Register the function to cancel event
// I do my stuffs
while ( true )
{
// Code ....
SomePreemptiveCall(); // The loop stucks here wating function to return
// Code ...
}
return 0; // Never comes here, but...
}
static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
Console.WriteLine("Exiting");
// Termitate what I have to terminate
Environment.Exit(-1);
}
}
It sounds like you have the threads directly terminating the application? Perhaps it would be better to have a thread signal the main thread to say that the application should be terminated.
On receiving this signal, the main thread can cleanly shutdown the other threads and finally close itself down.
ZeroKelvin's answer works in Windows 10 x64, .NET 4.6 console app. For those who do not need to deal with the CtrlType enum, here is a really simple way to hook into the framework's shutdown:
class Program
{
private delegate bool ConsoleCtrlHandlerDelegate(int sig);
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlHandlerDelegate handler, bool add);
static ConsoleCtrlHandlerDelegate _consoleCtrlHandler;
static void Main(string[] args)
{
_consoleCtrlHandler += s =>
{
//DoCustomShutdownStuff();
return false;
};
SetConsoleCtrlHandler(_consoleCtrlHandler, true);
}
}
Returning FALSE from the handler tells the framework that we are not "handling" the control signal, and the next handler function in the list of handlers for this process is used. If none of the handlers returns TRUE, the default handler is called.
Note that when the user performs a logoff or shutdown, the callback is not called by Windows but is instead terminated immediately.
There is for WinForms apps;
Application.ApplicationExit += CleanupBeforeExit;
For Console apps, try
AppDomain.CurrentDomain.DomainUnload += CleanupBeforeExit;
But I am not sure at what point that gets called or if it will work from within the current domain. I suspect not.
Visual Studio 2015 + Windows 10
Allow for cleanup
Single instance app
Some goldplating
Code:
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
namespace YourNamespace
{
class Program
{
// if you want to allow only one instance otherwise remove the next line
static Mutex mutex = new Mutex(false, "YOURGUID-YOURGUID-YOURGUID-YO");
static ManualResetEvent run = new ManualResetEvent(true);
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
private delegate bool EventHandler(CtrlType sig);
static EventHandler exitHandler;
enum CtrlType
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}
private static bool ExitHandler(CtrlType sig)
{
Console.WriteLine("Shutting down: " + sig.ToString());
run.Reset();
Thread.Sleep(2000);
return false; // If the function handles the control signal, it should return TRUE. If it returns FALSE, the next handler function in the list of handlers for this process is used (from MSDN).
}
static void Main(string[] args)
{
// if you want to allow only one instance otherwise remove the next 4 lines
if (!mutex.WaitOne(TimeSpan.FromSeconds(2), false))
{
return; // singleton application already started
}
exitHandler += new EventHandler(ExitHandler);
SetConsoleCtrlHandler(exitHandler, true);
try
{
Console.BackgroundColor = ConsoleColor.Gray;
Console.ForegroundColor = ConsoleColor.Black;
Console.Clear();
Console.SetBufferSize(Console.BufferWidth, 1024);
Console.Title = "Your Console Title - XYZ";
// start your threads here
Thread thread1 = new Thread(new ThreadStart(ThreadFunc1));
thread1.Start();
Thread thread2 = new Thread(new ThreadStart(ThreadFunc2));
thread2.IsBackground = true; // a background thread
thread2.Start();
while (run.WaitOne(0))
{
Thread.Sleep(100);
}
// do thread syncs here signal them the end so they can clean up or use the manual reset event in them or abort them
thread1.Abort();
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("fail: ");
Console.ForegroundColor = ConsoleColor.Black;
Console.WriteLine(ex.Message);
if (ex.InnerException != null)
{
Console.WriteLine("Inner: " + ex.InnerException.Message);
}
}
finally
{
// do app cleanup here
// if you want to allow only one instance otherwise remove the next line
mutex.ReleaseMutex();
// remove this after testing
Console.Beep(5000, 100);
}
}
public static void ThreadFunc1()
{
Console.Write("> ");
while ((line = Console.ReadLine()) != null)
{
if (line == "command 1")
{
}
else if (line == "command 1")
{
}
else if (line == "?")
{
}
Console.Write("> ");
}
}
public static void ThreadFunc2()
{
while (run.WaitOne(0))
{
Thread.Sleep(100);
}
// do thread cleanup here
Console.Beep();
}
}
}
The link mentioned above by Charle B in comment to flq
Deep down says:
SetConsoleCtrlHandler won't work on windows7 if you link to user32
Some where else in the thread it is suggested to crate a hidden window. So I create a winform and in onload I attached to console and execute original Main.
And then SetConsoleCtrlHandle works fine (SetConsoleCtrlHandle is called as suggested by flq)
public partial class App3DummyForm : Form
{
private readonly string[] _args;
public App3DummyForm(string[] args)
{
_args = args;
InitializeComponent();
}
private void App3DummyForm_Load(object sender, EventArgs e)
{
AllocConsole();
App3.Program.OriginalMain(_args);
}
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AllocConsole();
}
For those interested in VB.net. (I searched the internet and couldn't find an equivalent for it) Here it is translated into vb.net.
<DllImport("kernel32")> _
Private Function SetConsoleCtrlHandler(ByVal HandlerRoutine As HandlerDelegate, ByVal Add As Boolean) As Boolean
End Function
Private _handler As HandlerDelegate
Private Delegate Function HandlerDelegate(ByVal dwControlType As ControlEventType) As Boolean
Private Function ControlHandler(ByVal controlEvent As ControlEventType) As Boolean
Select Case controlEvent
Case ControlEventType.CtrlCEvent, ControlEventType.CtrlCloseEvent
Console.WriteLine("Closing...")
Return True
Case ControlEventType.CtrlLogoffEvent, ControlEventType.CtrlBreakEvent, ControlEventType.CtrlShutdownEvent
Console.WriteLine("Shutdown Detected")
Return False
End Select
End Function
Sub Main()
Try
_handler = New HandlerDelegate(AddressOf ControlHandler)
SetConsoleCtrlHandler(_handler, True)
.....
End Sub
I am trying to update the progress bar as per the time taken by a function(which I wrote here in numerical terms) to be processed.But it only shows the last called value.
public static void updateProgress(int x)
{
Program.f.progressBar1.Visible = true;
Program.f.progressBar1.Enabled = true;
Program.f.progressBar1.Value +=x;
Thread.Sleep(5000);
}
above fn is used to update the progress bar.
public static Form1 f;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
f = new Form1();
f.progressBar1.Maximum = 100;
f.progressBar1.Minimum = 0;
f.progressBar1.Value = 0;
updateProgress(25); //fn1
updateProgress(50); //fn2
Application.Run(f);
}
The progressBar directly shows 75% progress.
Thanks
Wrong: you are doing something before form is displayed:
static void Main()
{
f = new Form1(); // form instance is created
f.progressBar1.Maximum = 100;
f.progressBar1.Minimum = 0;
f.progressBar1.Value = 0;
updateProgress(25); // you do something and change property
updateProgress(50); // you do something and change property
Application.Run(f); // here form is displayed and you see the most recent change
}
Correct: to simulate work, which run in background (while form is displayed) you can do something like:
static void Main()
{
f = new Form1(); // form instance is created
f.progressBar1.Maximum = 100;
f.progressBar1.Minimum = 0;
f.progressBar1.Value = 0;
// create and start task running in parallel
Task.Run(() =>
{
Thread.Sleep(3000); // wait long enough until form is displayed
updateProgress(25);
updateProgress(50);
});
Application.Run(f);
}
public static void updateProgress(int x)
{
// Invoke is required because we run it in another thread
f.Invoke((MethodInvoker)(() =>
{
Program.f.progressBar1.Visible = true;
Program.f.progressBar1.Enabled = true;
Program.f.progressBar1.Value +=x;
}));
Thread.Sleep(5000); // simulate work
}
I am having a program.cs that is something like this :
namespace SumSwamp
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
But when I run the program it executes without any errors But the form1 is not being displayed. Please tell me if am doing something wrong
Here is my form class.
From your posted code, your error lies in this piece;
public static Boolean WaitForRoll = true;
public static int Turn = 0;
public Form1()
{
InitializeComponent();
this.Load += new EventHandler(this.Form1_Load);
while(Turn == 0) //always true
{
if (WaitForRoll==false) //always false
{
//never reached code
DieTotal=DieLargeNum;
Random rnd1 = new Random();
DieLargeNum = rnd1.Next(1, 7);
if (DieTotal>DieLargeNum)
{
Turn = 1;
labelStatus.Text = "Player 1's Turn";
WaitForRoll=true;
}
else
{
Turn = 2;
labelStatus.Text = "Player 2's Turn";
WaitForRoll = false;
}
}
}
//...
}
Look at it closely and you will find that your code never leaves the first while loop, and thus the constructor never comes to an end resulting in the Form1 object never to be created.
Some tips;
Rethink your design. You should not place this code in your constructor, but in methods.
Read up on while loops. They are a pain if used incorrectly, which you did.
Your Form1 is not visible because there is an infinite loop in your code. Please check the following code it goes infinite.
while ((CompSum < TotalSpaces) & (PlayerSum < TotalSpaces))
{
...
}
In our app we have a tracing window that we can enable on client locations to allow some debugging, it is accessed thought a static library.
Problem is, when there are a lot of log messages going to the window it crashes with an AccessViolation error. The link of code where is crashes is the RichTextBox.AppendText(..,..,..).
Here is where we create the window.
public static void Start(Form parent)
{
if (_runningThread == null || !_runningThread.IsAlive)
{
_runningThread = new Thread(() =>
{
_traceView = new TraceView(parent) { Text = "Tracing ~ " + parent.Text };
Application.Run(_traceView);
});
_runningThread.SetApartmentState(ApartmentState.MTA);
_runningThread.Start();
}
}
and here is were we write a line to the textbox
public void Write(string line, Color color)
{
try
{
_msgQueue.Enqueue(new Tuple<string, Color>(line, color));
MethodInvoker gui = delegate
{
try
{
// Was getting an overflow so trim out some lines
if (uiTrace.Lines.Length > 5000)
{
uiTrace.Lines = new string[0];
uiTrace.SelectionStart = uiTrace.TextLength;
Application.DoEvents();
}
while (_msgQueue.Count != 0)
{
bool retry;
var count = 0;
do
{
try
{
count++;
if (_indent < 0)
_indent = 0;
var msg = _msgQueue.Dequeue();
var selectionStart = uiTrace.TextLength;
uiTrace.AppendText(string.Format("[{0}] {1}{2}", _stopwatch.ElapsedMilliseconds, string.Empty.PadLeft(_indent * 4), msg.Item1));
uiTrace.Select(selectionStart, uiTrace.TextLength);
uiTrace.SelectionColor = msg.Item2;
uiTrace.SelectionStart = uiTrace.TextLength;
uiTrace.ScrollToCaret();
retry = false;
}
catch (Exception)
{
retry = true;
}
} while (retry && count < 5);
}
}
catch (Exception)
{
// We don't care about exceptions in here, for now anyway
}
};
if (uiTrace.InvokeRequired && !uiTrace.Disposing && !uiTrace.IsDisposed)
{
uiTrace.BeginInvoke(gui);
return;
}
gui();
}
catch (Exception)
{
// QIT_Backoffice.Processes.Errors.ErrorHandler.WriteErrorLog(Sources.SourceEnum.External, ex, "Error writing to trace");
}
}
I really have no idea how to get around this one, I thought calling BeginInvoke() is what was needed.
Looking for any help possible, or if anyone knows a third party tool that could handle this better I am happy to look at that.
Below is my modification of your logger. Note how _processing and lock are used to avoid reentrancy and protect _queue. Also, I use SynchronizationContext instead of Control.BeginInvoke to avoid any dependency on the window disposition state. TraceView can be created (with TraceView.Create) and used from any thread, but its window belongs to the parent window's thread and that's also where it's delivering text into richedit. It's possible to have a dedicated STA thread for that, but I don't feel that's necessary.
[EDITED] I've eliminated what might be a race condition in checking for _processing and added CreateOnOwnThread in case a dedicated thread for the logger UI is a requirement. I also decided to keep Application.DoEvents() for cases when Write is called from a tight loop, to keep the UI responsive.
Usage (stress-test):
private void Form1_Load(object sender, EventArgs ev)
{
var traceView = TraceView.Create(this);
for (var i = 0; i < 1000; i++)
{
var _i = i;
Task.Run(() =>
{
traceView.Write(String.Format("Line: {0}\n", _i), System.Drawing.Color.Green);
});
}
}
Implementation:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Logger
{
public partial class TraceView : Form
{
private Form _parent = null;
private SynchronizationContext _context = SynchronizationContext.Current;
private int _threadId = Thread.CurrentThread.ManagedThreadId;
private object _lock = new Object(); // sync lock to protect _queue and _processing
private Queue<Tuple<string, Color>> _queue = new Queue<Tuple<string, Color>>();
private volatile bool _processing = false; // reentracy check flag
public TraceView(Form parent)
{
_parent = parent;
InitializeComponent();
}
public static TraceView Create(Form parent)
{
TraceView view = null;
// create it on the parent window's thread
parent.Invoke(new Action(() => {
view = new TraceView(parent);
view.Show(parent);
}));
return view;
}
private void DequeueMessages()
{
// make sure we are on the UI thread
Debug.Assert(Thread.CurrentThread.ManagedThreadId == _threadId);
lock (_lock)
{
// prevent re-entracy
if (_processing)
return;
// mark the beginning of processing
_processing = true;
}
// process pending messages
for (; ; )
{
Tuple<string, Color> msg = null;
lock (_lock)
{
if (!_queue.Any())
{
// mark the end of processing
_processing = false;
return;
}
msg = _queue.Dequeue();
}
if (this.Disposing || this.IsDisposed)
{
// do not just loose messages if the window is disposed
Trace.Write(msg.Item1);
}
else
{
var selectionStart = _richTextBox.TextLength;
_richTextBox.AppendText(msg.Item1);
_richTextBox.Select(selectionStart, _richTextBox.TextLength);
_richTextBox.SelectionColor = msg.Item2;
_richTextBox.SelectionStart = _richTextBox.TextLength;
_richTextBox.ScrollToCaret();
_richTextBox.Refresh(); // redraw;
// DoEvents is required if logging from a tight loop,
// to keep the UI responsive
Application.DoEvents();
}
}
}
public void Write(string line, Color color)
{
lock (_lock)
{
_queue.Enqueue(new Tuple<string, Color>(line, color));
// prevent re-entracy
if (_processing)
return; // DequeueMessages is already in progress
}
if (Thread.CurrentThread.ManagedThreadId == _threadId)
DequeueMessages();
else
_context.Post((_) =>
{
DequeueMessages();
}, null);
}
public static TraceView CreateOnOwnThread()
{
TraceView view = null;
using (var sync = new ManualResetEventSlim())
{
// create it on its own thread
var thread = new Thread(() =>
{
SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
view = new TraceView(null);
view.Show();
sync.Set(); // ready Write calls
Application.Run(view); // view does Application.ExitThread() when closed
return;
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
sync.Wait();
}
return view;
}
}
}
I have a lot more .Net experience with VB than C#, but doesn't the following code:
if (uiTrace.InvokeRequired && !uiTrace.Disposing && !uiTrace.IsDisposed)
{
uiTrace.BeginInvoke(gui);
return;
}
gui();
result in gui being invoked if InvokeRequired etc. in the If statement, as well as being executed (again) in the current (presumably non-UI) thread in gui().
Wouldn't:
If (uiTrace.InvokeRequired && !uiTrace.Disposing && !uiTrace.IsDisposed)
{
uiTrace.BeginInvoke(gui);
return;
}
Else
gui();
be more appropriate?