NAudio NullReferenceException when using a Start/Stop button - c#

I have a GUI form with a checkbox button for Start/Stop. When the program starts, clicking Start and Stop works once. When I try and click Start again after I stop the recording, I get a NullReferenceException.
An unhandled exception of type 'System.NullReferenceException' occurred in NAudio.dll
Additional information: Object reference not set to an instance of an object.
at this line in my Program.cs file:
Application.Run(new GUI());
Here is my Start/Stop button in my GUI form:
public GUI()
{
InitializeComponent();
InitializeAudio();
}
private void btnStartStop_CheckedChanged(object sender, EventArgs e)
{
if (btnStartStop.Checked)
{
waveInDevice.StartRecording();
waveOutDevice.Play();
btnStartStop.Text = "Stop";
}
else
{
btnStartStop.Text = "Start";
waveInDevice.StopRecording();
waveOutDevice.Stop();
}
}
private void InitializeAudio()
{
buffer = new BufferedWaveProvider(waveInDevice.WaveFormat);
buffer.DiscardOnBufferOverflow = true;
waveInDevice.DataAvailable += new EventHandler<WaveInEventArgs>(waveInDevice_DataAvailable);
waveOutDevice.Init(buffer);
}

Related

UWP MediaEnded event handler for MediaPlayerElement Throws System.ArgumentException

First off I'm fairly new to UWP so if this question is stupid, my apologies.
What I'm attempting to do is set the event handler for when the song has finnished so that I can start the next one. However when launching I get thrown the following error after the program has started Exception thrown: 'System.ArgumentException' in System.Private.CoreLib.ni.dll
An exception of type 'System.ArgumentException' occurred in System.Private.CoreLib.ni.dll but was not handled in user code
Delegate to an instance method cannot have null 'this'.
This error traces back to mediaPlayer.MediaPlayer.MediaEnded += MediaPlayer_MediaEnded1;
I suspect that I'm incorrectly setting the handler.
<MediaPlayerElement x:Name="mediaPlayer" AreTransportControlsEnabled="True" Margin="0,0,0,0"/>
Here is my code
List<Song> songs = new List<Song>();
//private MediaPlayerElement PlayMusic = new MediaPlayerElement();
private int curSongIndex = 0;
private IReadOnlyList<StorageFile> files;
public MainPage(){
this.InitializeComponent();
slist.ItemClick += Slist_ItemClick;
mediaPlayer.MediaPlayer.MediaEnded += MediaPlayer_MediaEnded1;
}
private void MediaPlayer_MediaEnded1(Windows.Media.Playback.MediaPlayer sender, object args) {
playNextSong();
}
private void Play(Song song) {
mediaPlayer.Source = MediaSource.CreateFromStorageFile(song.File);
mediaPlayer.MediaPlayer.Play();
AlbumArt.Source = song.Art;
}
private void Slist_ItemClick(object sender, ItemClickEventArgs e) {
for(int i = 0; i < songs.Count; i++) {
if (e.ClickedItem.Equals(songs[i])) {
Play(songs[i]);
curSongIndex = i;
}
}
}

Why does subscription to Application.ThreadException swallow the exception?

Suppose I have an exception throw in the message loop:
private void timer1_Tick(object sender, EventArgs e)
{
throw new Exception("yehaaaa!!!!");
}
By default, this throws & displays the generic error dialog to user. (that's what I want)
However if I add the following subscription to Application.ThreadException:
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
//_raygunClient.Send(e.Exception);
}
Then the exception is swallowed.
Why?
& how can I have it throw to the user normally?
It's all right there in the reference source:
internal void OnThreadException(Exception t) {
if (GetState(STATE_INTHREADEXCEPTION)) return;
SetState(STATE_INTHREADEXCEPTION, true);
try {
if (threadExceptionHandler != null) {
threadExceptionHandler(Thread.CurrentThread, new ThreadExceptionEventArgs(t));
}
else {
if (SystemInformation.UserInteractive) {
ThreadExceptionDialog td = new ThreadExceptionDialog(t);
If there is a handler it is invoked otherwise some standard code is run. If you want to show the standard dialog, use ThreadExceptionDialog and handle the DialogResult the same way. In my own code there is something to this effect, which seems to work:
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
Exception exception = e.Exception;
_Logger.Error(e.Exception, "An unhandled forms application exception occurred");
// Show the same default dialog
if (SystemInformation.UserInteractive)
{
using (ThreadExceptionDialog dialog = new ThreadExceptionDialog(exception))
{
if (dialog.ShowDialog() == DialogResult.Cancel)
return;
}
Application.Exit();
Environment.Exit(0);
}
}

Delegate loads the Alert Form but I can't use any of the components.. its stuck

The problem is below. Here's my code...
// Contents of Form1.cs
// Usual includes
namespace ProcessMonitor
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public Boolean getStatus()
{
// Returns true if the system is active
if (label1.Text.Equals("Active"))
return true;
return false;
}
private void button1_Click(object sender, EventArgs e)
{
if(getStatus())
{
label1.Text = "Not Active";
button1.Text = "Activate";
}
else
{
label1.Text = "Active";
button1.Text = "Deactivate";
}
}
private void Form1_Load(object sender, EventArgs e)
{
Monitor mon = new Monitor(this);
mon.Run();
}
}
}
// Contents of Monitor.cs
// Usual includes
using System.Management;
using System.Diagnostics;
using System.Threading;
namespace ProcessMonitor
{
class Monitor
{
Form1 parent;
private void ShowAlert(Alert al)
{
al.Show();
}
public Monitor(Form1 parent)
{
this.parent = parent;
}
public void InvokeMethod()
{
//This function will be on main thread if called by Control.Invoke/Control.BeginInvoke
Alert frm = new Alert(this.parent);
frm.Show();
}
// This method that will be called when the thread is started
public void Run()
{
var query = new WqlEventQuery("__InstanceCreationEvent", new TimeSpan(0, 0, 0, 0, 1),
"TargetInstance isa \"Win32_Process\");
while (true)
{
using (var watcher = new ManagementEventWatcher(query))
{
ManagementBaseObject mo = watcher.WaitForNextEvent();a
//MessageBox.Show("Created process: " + ((ManagementBaseObject)mo["TargetInstance"])["Name"] + ",Path: " + ((ManagementBaseObject)mo["TargetInstance"])["ExecutablePath"]);
ManagementBaseObject o = (ManagementBaseObject)mo["TargetInstance"];
String str = "";
foreach (PropertyData s in o.Properties)
{
str += s.Name + ":" + s.Value + "\n";
}
this.parent.Invoke(new MethodInvoker(InvokeMethod), null);
}
}
}
}
}
Alert.cs is just a blank form with a label that says “new process has started”. I intend to display the name of the process and location, pid, etc. by passing it to this alert form via the Thread (i.e. class Monitor). I have deliberately made the thread load in form_load so that I can resolve this error first. Adding it as a thread properly after the main form loads fully is a later task. I need to fix this first..
The delegate creates the Alert form but I can’t click on it, its just stuck. Need help to solve this.
Your while loop in Run is blocking the UI thread.
by passing it to this alert form via the Thread
You never actually create a new thread or task here - you just run code which executes in the UI thread, and causes an infinite loop. This will prevent the main form, as well as your Alert form, from ever displaying messages.
You need to push this into a background thread in order for it to work, ie:
private void Form1_Load(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(_ =>
{
Monitor mon = new Monitor(this);
mon.Run();
});
}

Exception when closing Form (thread + invoke)

I have just started to learn about threads and methodinvoking in c#, but I have come across a problem which I couldn't find the solution of.
I made a basic C# form program which keeps updating and displaying a number, by starting a thread and invoke delegate.
Starting new thread on Form1_load:
private void Form1_Load(object sender, EventArgs e)
{
t = new System.Threading.Thread(DoThisAllTheTime);
t.Start();
}
Public void DoThisAllTheTime (which keeps updating the number) :
public void DoThisAllTheTime()
{
while(true)
{
if (!this.IsDisposed)
{
number += 1;
MethodInvoker yolo = delegate() { label1.Text = number.ToString(); };
this.Invoke(yolo);
}
}
}
Now when I click the X button of the form, I get the following exception:
'An unhandled exception of type 'System.ObjectDisposedException' occurred in System.Windows.Forms.dll
Can't update a deleted object'
While I actually did check if the form was disposed or not.
EDIT: I added catch (ObjectDisposedException ex) to the code which fixed the problem.
Working code:
public void DoThisAllTheTime()
{
while(true)
{
number += 1;
try {
MethodInvoker yolo = delegate() { label1.Text = number.ToString(); };
this.Invoke(yolo);
}
catch (ObjectDisposedException ex)
{
t.Abort();
}
}
}
Your call to this.IsDisposed is always out of date. You need to intercept your form closing event and stop the thread explicitly. Then you won't have to do that IsDisposed test at all.
There are many ways you can do this. Personally, I would use the System.Threading.Tasks namespace, but if you want to keep your use of System.Threading, you should define a member variable _updateThread, and launch it in your load event:
_updateThread = new System.Threading.Thread(DoThisAllTheTime);
_updateThread.Start();
Then in your closing event:
private void Form1_Closing(object sender, CancelEventArgs e)
{
_stopCounting = true;
_updateThread.Join();
}
Finally, replace the IsDisposed test with a check on the value of your new _stopCounting member variable:
public void DoThisAllTheTime()
{
MethodInvoker yolo = delegate() { label1.Text = number.ToString(); };
while(!_stopCounting)
{
number += 1;
this.Invoke(yolo);
}
}
Just put this override in your form class:
protected override void OnClosing(CancelEventArgs e) {
t.Abort();
base.OnClosing(e);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Thread.CurrentThread.Abort();
}

BackgroundWorker thread is not stopping winforms c#

I am using BackgroundWorker thread to call a small routine which is receiving messages from MSMQ as soon as the message comes to MSMQ queue(messages comes to msmq in every 5 seconds) it comes to my application which is using BackgroundWorker thread. Below is my Win Form class. I am new to threading so please appology if I am doing something wrong
Problem: My application is MDI application, when I am executing my application first time it works perfectly fine and receives the MSMQ message as soon as it comes to the queue, which is every 5 seconds but when ever I close this form which is a child form it closes fine, but right after opening this same form I am receiving messages from MSMQ with 10 seconds of dalay, so it means I am messing up something in the background worker thread, I tried to cancel this background worker thread but I am failed and unable to properly cancle or terminate the thread. Please help and share your experience. below is my form code.
public partial class FrmBooking : BookingManager.Core.BaseForm.BaseForm
{
internal const string queName = #"messageServer\private$\Response";
private Int32 counter = 0;
BackgroundWorker backgroundWorker1 = new BackgroundWorker();
public FrmBooking()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
backgroundWorker1.RunWorkerCompleted+=new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.ProgressChanged+=new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.DoWork+=new DoWorkEventHandler(backgroundWorker1_DoWork);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bgWorker = sender as BackgroundWorker;
if (bgWorker.CancellationPending)
{
e.Cancel = true;
return;
}
try
{
MessageQueue messageQueue = null;
if (MessageQueue.Exists(queName))
{
messageQueue = new MessageQueue(queName);
}
else
{
MessageQueue.Create(queName);
}
messageQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(String) });
System.Messaging.Message msg = messageQueue.Receive();
bgWorker.ReportProgress(100, msg);
}
catch (Exception ex) { }
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (!e.Cancelled)
{
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
System.Messaging.Message msg = e.UserState as System.Messaging.Message;
listBoxControl1.Items.Add(msg.Body.ToString());
counter++;
labelControl1.Text = String.Format("Total messages received {0}", counter.ToString());
}
private void FrmBooking_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
}
You have two options here:
1) In the Form's Closing event, call backgroundWorker1.CancelAsync().
2) A better approach would be to remove your background worker altogether and use the the MessageQueue's native asynchronous processing mechanism for this. You can start the queue request using the BeginReceive method after adding a ReceivedCompleted event handler, then in the completed event handler, process the message and restart the request.
The issue is that if you issue a Receive request, it will block the background worker thread until a message is received in the queue, and CancelAsync will only request that the background worker be stopped, it won't cancel the Receive request.
For example (updated):
public partial class FrmBooking : BookingManager.Core.BaseForm.BaseForm
{
public FrmBooking()
{
InitializeComponent();
this.FormClosing += new FormClosingEventHandler(FrmBooking_FormClosing);
}
internal const string queName = #"messageServer\private$\Response";
private Int32 counter = 0;
private MessageQueue messageQueue = null;
private bool formIsClosed = false;
private void FrmBooking_Load(object sender, EventArgs e)
{
StartQueue();
}
void FrmBooking_FormClosing(object sender, FormClosingEventArgs e)
{
// Set the flag to indicate the form is closed
formIsClosed = true;
// If the messagequeue exists, close it
if (messageQueue != null)
{
messageQueue.Close();
}
}
private void StartQueue()
{
if (MessageQueue.Exists(queName))
{
messageQueue = new MessageQueue(queName);
}
else
{
MessageQueue.Create(queName);
}
messageQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(String) });
// Add an event handler for the ReceiveCompleted event.
messageQueue.ReceiveCompleted += new ReceiveCompletedEventHandler(MessageReceived);
messageQueue.BeginReceive(TimeSpan.FromSeconds(15));
}
// Provides an event handler for the ReceiveCompleted event.
private void MessageReceived(Object source, ReceiveCompletedEventArgs asyncResult)
{
if (!this.formIsClosed)
{
// End the asynchronous receive operation.
System.Messaging.Message msg = messageQueue.EndReceive(asyncResult.AsyncResult);
// Display the message information on the screen.
listBoxControl1.Items.Add(msg.Body.ToString());
counter++;
labelControl1.Text = String.Format("Total messages received {0}", counter.ToString());
// Start receiving the next message
messageQueue.BeginReceive(TimeSpan.FromSeconds(15));
}
}
}
When you close the form, do you terminate the worker? If not, if there is a reference to the form or to the worker somewhere (event handlers?) then it will not get GCd and stays around. Upon opening the second instance you may have two background workers running....

Categories

Resources