FileSystemWatcher with a background thread is missing to move files - c#

I have a simple requirement of moving files from source folder to destination folder. The files are about 5mb in size and arrive three at a time (every 5 seconds).
The current mechanism I have in place seems to move files however if the destination folder is not accessible for a few seconds, the files to process from the source directory does not queue up but gets missed.
My question is how do I create a queue with all the files which are created at source directory and move the files to destination? Do i need to use the background thread?
My watcher code looks like this.
public sealed class Watcher
{
int eventCount = 0;
#region Private Members
/// <summary>
/// File system watcher variable.
/// </summary>
private FileSystemWatcher fsw = null;
/// <summary>
/// Destination path to use.
/// </summary>
private string destination = #"c:\temp\doc2\";
/// <summary>
/// Source path to monitor.
/// </summary>
private string source = #"c:\temp\doc\";
/// <summary>
/// Default filter type is all files.
/// </summary>
private string filter = "*.bmp";
/// <summary>
/// Monitor all sub directories in the source folder.
/// </summary>
private bool includeSubdirectories = true;
/// <summary>
/// Background worker which will Move files.
/// </summary>
private BackgroundWorker bgWorker = null;
/// <summary>
/// Toggle flag to enable copying files and vice versa.
/// </summary>
private bool enableCopyingFiles = false;
/// <summary>
/// File System watcher lock.
/// </summary>
private object fswLock = new object();
private static Watcher watcherInstance;
#endregion
#region Public Properties
public static Watcher WatcherInstance
{
get
{
if (watcherInstance == null)
{
watcherInstance = new Watcher();
}
return watcherInstance;
}
}
public string Source
{
get
{
return source;
}
set
{
source = value;
}
}
public string Destination
{
get
{
return destination;
}
set
{
destination = value;
}
}
public string Filter
{
get
{
return filter;
}
set
{
filter = value;
}
}
public bool MonitorSubDirectories
{
get
{
return includeSubdirectories;
}
set
{
includeSubdirectories = value;
}
}
public bool EnableCopyingFiles
{
get
{
return enableCopyingFiles;
}
set
{
enableCopyingFiles = value;
}
}
public FileSystemWatcher FSW
{
get
{
return fsw;
}
set
{
fsw = value;
}
}
#endregion
#region Construction
/// <summary>
/// Constructor.
/// </summary>
public Watcher()
{
// Intentionally left blank.
}
#endregion
#region Public Methods
/// <summary>
/// Method which will initialise the required
/// file system watcher objects to starting watching.
/// </summary>
public void InitialiseFSW()
{
fsw = new FileSystemWatcher();
bgWorker = new BackgroundWorker();
}
/// <summary>
/// Method which will start watching.
/// </summary>
public void StartWatch()
{
if (fsw != null)
{
fsw.Path = source;
fsw.Filter = filter;
fsw.IncludeSubdirectories = includeSubdirectories;
fsw.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.LastAccess;
// Setup events.
fsw.Created += fsw_Created;
// Important to set the below otherwise no events will be raised.
fsw.EnableRaisingEvents = enableCopyingFiles;
bgWorker.DoWork += bgWorker_DoWork;
}
else
{
Trace.WriteLine("File System Watcher is not initialised. Setting ISS Fault Alarm Bit");
//CommonActions.SetAlarmBit(ApplicationConstants.tag_AlarmTag, ApplicationConstants.bit_ISSFault);
}
}
/// <summary>
/// Method to stop watch.
/// </summary>
public void StopWatch()
{
// Stop Watcher.
if (bgWorker != null)
{
bgWorker.DoWork -= bgWorker_DoWork;
}
if (fsw != null)
{
fsw.Created -= fsw_Created;
}
}
#endregion
#region Private Methods
/// <summary>
/// Method which will do the work on the background thread.
/// Currently Move files from source to destination and
/// monitor disk capacity.
/// </summary>
/// <param name="sender">Object Sender</param>
/// <param name="e">Event Arguments</param>
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
Trace.WriteLine("ZZZZZ..Event Count:" + eventCount.ToString());
// Extract the file names form the arguments.
FileSystemEventArgs fsea = (FileSystemEventArgs)e.Argument;
// Form the correct filename.
// An assumption has been made that there will always be an '&' symbol in the filename.
// An assumption has been made that the batch code will be added before the first '&' symbol.
string newFileName = string.Empty;
//// First character we are looking for has been found.
//// Sanity checks.
//if (CommonActions.ExtDictionary != null)
//{
// // Add the batch Code.
// // newFileName = fnParts[i] + "_" + CommonActions.ExtDictionary["BatchID"] + "_" + "&";
// // Add the batch code before the filename for easy sorting in windows explorer.
// newFileName = CommonActions.ExtDictionary["BatchID"] + "_" + fsea.Name;
//}
//else
//{
// Batch Code not found. So prefix with hardcoded text.
newFileName = "BatchCode" + "_" + fsea.Name;
//newFileName = fsea.Name;
//}
// We should now have the fully formed filename now.
// Move the file to the new location
string destPath = destination + #"\" + newFileName;
var fi = new FileInfo(fsea.FullPath);
// TODO Check if the file exist.
if (File.Exists(Path.Combine(Source, fsea.Name)))
{
// Check if the file is accessiable.
if (IsAccessible(fi, FileMode.Open, FileAccess.Read))
{
if (!File.Exists(destPath))
{
try
{
// Copy the file.
//File.Copy(fsea.FullPath, destPath);
// Move the file.
//File.Move(fsea.FullPath, destPath);
File.Copy(fsea.FullPath, destPath);
File.SetAttributes(destPath, FileAttributes.ReadOnly);
//Stopwatch sWatch = Stopwatch.StartNew();
//TimeSpan fileDropTimeout = new TimeSpan(0, 0, 10);
//bool fileActionSuccess = false;
//do
//{
// // Copy the file.
// //File.Copy(fsea.FullPath, destPath);
// // Move the file.
// //File.Move(fsea.FullPath, destPath);
// File.Copy(fsea.FullPath, destPath);
// File.SetAttributes(destPath, FileAttributes.ReadOnly);
// fileActionSuccess = true;
//} while (sWatch.Elapsed < fileDropTimeout);
//if(!fileActionSuccess)
//{
// Trace.WriteLine("File Move or File Attribute settings failed.");
// throw new Exception();
//}
// Wait before checking for the file exists at destination.
Thread.Sleep(Convert.ToInt32(ConfigurationManager.AppSettings["ExistsAtDestination"]));
// Check if the file has actually been moved to dest.
if (!File.Exists(destPath))
{
// TODO Raise alarms here.
Trace.WriteLine("Failed to Move. File does not exist in destination. Setting ISS Fault Alarm bit");
//CommonActions.SetAlarmBit(ApplicationConstants.tag_AlarmTag, ApplicationConstants.bit_ISSFault);
// Notify HMI about the error type.
Trace.WriteLine("Failed to Move. File does not exist in destination. Setting ISS File Move Fault Alarm bit");
}
}
catch (Exception ex)
{
// TODO log the exception and Raise alarm?
Trace.WriteLine("Failed to Move or set attributes on file. Setting ISS Fault Alarm bit");
//CommonActions.SetAlarmBit(ApplicationConstants.tag_AlarmTag, ApplicationConstants.bit_ISSFault);
// Notify HMI about the error type.
Trace.WriteLine("Failed to Move or set attributes on file. Setting ISS File Move Fault Alarm bit");
}
}
else
{
Trace.WriteLine("File Move failed as the file: " + newFileName + " already exists in the destination folder");
}
}
else
{
Trace.WriteLine("File Move failed. File is not accessible");
}
}
}
/// <summary>
/// Event which is raised when a file is created in the folder which is being watched.
/// </summary>
/// <param name="sender">Object sender</param>
/// <param name="e">Event arguments</param>
private void fsw_Created(object sender, FileSystemEventArgs e)
{
lock (fswLock)
{
eventCount++;
// Start the background worker.
// Check whether if the background worker is busy if not continue.
if (!bgWorker.IsBusy)
{
bgWorker.RunWorkerAsync(e);
}
else
{
Trace.WriteLine("An attempt to use background worker for concurrent tasks has been encountered ");
// Worker thread is busy.
int busyCount = 0;
while (busyCount < 4)
{
// Wait for 500ms and try again.
Thread.Sleep(500);
if (!bgWorker.IsBusy)
{
bgWorker.RunWorkerAsync(e);
break;
}
else
{
Trace.WriteLine("An attempt to use background worker for concurrent tasks has been encountered, attempt " + busyCount);
busyCount++;
}
}
}
}
}
/// <summary>
/// Extension method to check if a file is accessible.
/// </summary>
/// <param name="fi">File Info</param>
/// <param name="mode">File Mode</param>
/// <param name="access">File Access</param>
/// <returns>Attempts three times. True if the file is accessible</returns>
private bool IsAccessible(FileInfo fi, FileMode mode, FileAccess access)
{
bool hasAccess = false;
int i = 0;
while (!hasAccess)
{
try
{
using (var fileStream = File.Open(fi.FullName, mode, access))
{
}
hasAccess = true;
i = 1;
break;
}
catch (Exception ex)
{
if (i < 4)
{
// We will swallow the exception, wait and try again.
Thread.Sleep(500);
// Explicitly set hasaccess flag.
hasAccess = false;
i++;
}
else
{
i = 0;
Trace.WriteLine("Failed to Move. File is not accessable. " + ex.ToString());
// Notify HMI
Trace.WriteLine("Failed to Move. File is not accessable.. Setting ISS Fault Alarm bit");
//CommonActions.SetAlarmBit(ApplicationConstants.tag_AlarmTag, ApplicationConstants.bit_ISSFault);
// Notify HMI about the error type.
Trace.WriteLine("Failed to Move. File is not accessable.. Setting ISS File Move Fault Alarm bit");
//CommonActions.SetAlarmBit(ApplicationConstants.tag_AlarmTag, ApplicationConstants.bit_ISSFileCopyFault);
// Explicitly set hasaccess flag.
hasAccess = false;
break;
}
}
}
// return hasAccess;
return true;
}
#endregion
}
I will start watching for file as below
private void CopyFiles(bool enableCopy)
{
if (enableCopy)
{
// Initialise watcher.
Watcher.WatcherInstance.InitialiseFSW();
// Set Source.
Watcher.WatcherInstance.Source = ConfigurationManager.AppSettings["Source"];
// Set Destination.
Watcher.WatcherInstance.Destination = ConfigurationManager.AppSettings["Destination"];
//Trace.WriteLine("FTP Destination is set to:" + Watcher.WatcherInstance.Destination);
// Set Filter
Watcher.WatcherInstance.Filter = "*.bmp";
// Watch subdirectories?
Watcher.WatcherInstance.MonitorSubDirectories = true;
// Enable events.
Watcher.WatcherInstance.EnableCopyingFiles = enableCopy;
// Start Watch.
Watcher.WatcherInstance.StartWatch();
}
else
{
//if (wchr != null && wchr.FSW != null)
//{
// Stop Watcher.
Watcher.WatcherInstance.StopWatch();
// Stop copying files. As the batch is stopped.
Watcher.WatcherInstance.FSW.EnableRaisingEvents = enableCopy;
//}
}
}

These are my findings and finally seem to move files without missing any files.
Background worker is not the correct thing to use
Create a task for each file and let it do its thing.
The updated watcher class looks like this.
public sealed class Watcher
{
int eventCount = 0;
#region Private Members
/// <summary>
/// File system watcher variable.
/// </summary>
private FileSystemWatcher fsw = null;
/// <summary>
/// Destination path to use.
/// </summary>
private string destination = #"c:\temp\doc2\";
/// <summary>
/// Source path to monitor.
/// </summary>
private string source = #"c:\temp\doc\";
/// <summary>
/// Default filter type is all files.
/// </summary>
private string filter = "*.bmp";
/// <summary>
/// Monitor all sub directories in the source folder.
/// </summary>
private bool includeSubdirectories = true;
/// <summary>
/// Background worker which will Move files.
/// </summary>
private BackgroundWorker bgWorker = null;
/// <summary>
/// Toggle flag to enable copying files and vice versa.
/// </summary>
private bool enableCopyingFiles = false;
/// <summary>
/// File System watcher lock.
/// </summary>
private object fswLock = new object();
private static Watcher watcherInstance;
#endregion
#region Public Properties
public static Watcher WatcherInstance
{
get
{
if (watcherInstance == null)
{
watcherInstance = new Watcher();
}
return watcherInstance;
}
}
public string Source
{
get
{
return source;
}
set
{
source = value;
}
}
public string Destination
{
get
{
return destination;
}
set
{
destination = value;
}
}
public string Filter
{
get
{
return filter;
}
set
{
filter = value;
}
}
public bool MonitorSubDirectories
{
get
{
return includeSubdirectories;
}
set
{
includeSubdirectories = value;
}
}
public bool EnableCopyingFiles
{
get
{
return enableCopyingFiles;
}
set
{
enableCopyingFiles = value;
}
}
public FileSystemWatcher FSW
{
get
{
return fsw;
}
set
{
fsw = value;
}
}
#endregion
#region Construction
/// <summary>
/// Constructor.
/// </summary>
public Watcher()
{
// Intentionally left blank.
}
#endregion
#region Public Methods
/// <summary>
/// Method which will initialise the required
/// file system watcher objects to starting watching.
/// </summary>
public void InitialiseFSW()
{
fsw = new FileSystemWatcher();
bgWorker = new BackgroundWorker();
}
/// <summary>
/// Method which will start watching.
/// </summary>
public void StartWatch()
{
if (fsw != null)
{
fsw.Path = source;
fsw.Filter = filter;
fsw.IncludeSubdirectories = includeSubdirectories;
fsw.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.LastAccess;
// Setup events.
fsw.Created += fsw_Created;
// Important to set the below otherwise no events will be raised.
fsw.EnableRaisingEvents = enableCopyingFiles;
bgWorker.DoWork += bgWorker_DoWork;
}
else
{
Trace.WriteLine("File System Watcher is not initialised. Setting ISS Fault Alarm Bit");
//CommonActions.SetAlarmBit(ApplicationConstants.tag_AlarmTag, ApplicationConstants.bit_ISSFault);
}
}
/// <summary>
/// Method to stop watch.
/// </summary>
public void StopWatch()
{
// Stop Watcher.
if (bgWorker != null)
{
bgWorker.DoWork -= bgWorker_DoWork;
}
if (fsw != null)
{
fsw.Created -= fsw_Created;
}
}
#endregion
#region Private Methods
/// <summary>
/// Method which will do the work on the background thread.
/// Currently Move files from source to destination and
/// monitor disk capacity.
/// </summary>
/// <param name="sender">Object Sender</param>
/// <param name="e">Event Arguments</param>
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
}
private void PerformFileActions(string sourcePath)
{
string extractedFileName = Path.GetFileName(sourcePath);
string newFileName = string.Empty;
newFileName = "BatchCode" + "_" + extractedFileName;
// We should now have the fully formed filename now.
// Move the file to the new location
string destPath = destination + #"\" + newFileName;
var fi = new FileInfo(sourcePath);
// TODO Check if the file exist.
if (File.Exists(Path.Combine(Source, extractedFileName)))
{
// Check if the file is accessiable.
if (IsAccessible(fi, FileMode.Open, FileAccess.Read))
{
if (!File.Exists(destPath))
{
try
{
File.Copy(sourcePath, destPath);
File.SetAttributes(destPath, FileAttributes.ReadOnly);
// Wait before checking for the file exists at destination.
Thread.Sleep(Convert.ToInt32(ConfigurationManager.AppSettings["ExistsAtDestination"]));
// Check if the file has actually been moved to dest.
if (!File.Exists(destPath))
{
// TODO Raise alarms here.
Trace.WriteLine("Failed to Move. File does not exist in destination. Setting ISS Fault Alarm bit");
//CommonActions.SetAlarmBit(ApplicationConstants.tag_AlarmTag, ApplicationConstants.bit_ISSFault);
// Notify HMI about the error type.
Trace.WriteLine("Failed to Move. File does not exist in destination. Setting ISS File Move Fault Alarm bit");
}
}
catch (Exception ex)
{
// TODO log the exception and Raise alarm?
Trace.WriteLine("Failed to Move or set attributes on file. Setting ISS Fault Alarm bit");
//CommonActions.SetAlarmBit(ApplicationConstants.tag_AlarmTag, ApplicationConstants.bit_ISSFault);
// Notify HMI about the error type.
Trace.WriteLine("Failed to Move or set attributes on file. Setting ISS File Move Fault Alarm bit");
}
}
else
{
Trace.WriteLine("File Move failed as the file: " + newFileName + " already exists in the destination folder");
}
}
else
{
Trace.WriteLine("File Move failed. File is not accessible");
}
}
}
/// <summary>
/// Event which is raised when a file is created in the folder which is being watched.
/// </summary>
/// <param name="sender">Object sender</param>
/// <param name="e">Event arguments</param>
private void fsw_Created(object sender, FileSystemEventArgs e)
{
lock (fswLock)
{
DateTime lastRead = DateTime.MinValue;
DateTime lastWriteTime = File.GetCreationTime(e.FullPath);
if (lastWriteTime != lastRead)
{
eventCount++;
// Start a new task and forget.
Task.Factory.StartNew(() => {
PerformFileActions(e.FullPath);
});
lastRead = lastWriteTime;
}
}
}
/// <summary>
/// Extension method to check if a file is accessible.
/// </summary>
/// <param name="fi">File Info</param>
/// <param name="mode">File Mode</param>
/// <param name="access">File Access</param>
/// <returns>Attempts three times. True if the file is accessible</returns>
private bool IsAccessible(FileInfo fi, FileMode mode, FileAccess access)
{
bool hasAccess = false;
int i = 0;
while (!hasAccess)
{
try
{
using (var fileStream = File.Open(fi.FullName, mode, access))
{
}
hasAccess = true;
i = 1;
break;
}
catch (Exception ex)
{
if (i < 4)
{
// We will swallow the exception, wait and try again.
Thread.Sleep(500);
// Explicitly set hasaccess flag.
hasAccess = false;
i++;
}
else
{
i = 0;
Trace.WriteLine("Failed to Move. File is not accessable. " + ex.ToString());
// Notify HMI
Trace.WriteLine("Failed to Move. File is not accessable.. Setting ISS Fault Alarm bit");
//CommonActions.SetAlarmBit(ApplicationConstants.tag_AlarmTag, ApplicationConstants.bit_ISSFault);
// Notify HMI about the error type.
Trace.WriteLine("Failed to Move. File is not accessable.. Setting ISS File Move Fault Alarm bit");
//CommonActions.SetAlarmBit(ApplicationConstants.tag_AlarmTag, ApplicationConstants.bit_ISSFileCopyFault);
// Explicitly set hasaccess flag.
hasAccess = false;
break;
}
}
}
// return hasAccess;
return true;
}
#endregion
}

Related

How to play multiple sounds at once in C#

I want to be able to play multiple sounds at once. I tried this using multi threading but found they would still play one after the other. Is there a way to get them to play at the same time?
static void Main(string[] args)
{
Console.WriteLine("Hello World");
Thread th = new Thread(playSound);
Thread th1 = new Thread(playSound1);
th.Start();
th1.Start();
}
public static void playSound()
{
System.Media.SoundPlayer s1 = new System.Media.SoundPlayer(#"c:\Users\Ben\Documents\c#\note_c.wav");
s1.Load();
s1.PlaySync();
}
public static void playSound1()
{
System.Media.SoundPlayer s1 = new System.Media.SoundPlayer(#"c:\Users\Ben\Documents\c#\note_e.wav");
s1.Load();
s1.PlaySync();
}
}
How about if we schedule a parallel execution.
Like that:
var files = new List<string>() {"note_1.wav", "note_2.wav"};
Parallel.ForEach(files, (currentFile) =>
{
System.Media.SoundPlayer s1 = new System.Media.SoundPlayer(currentFile);
s1.Load();
s1.PlaySync();
});
Try using
[DllImport("winmm.dll")]
static extern Int32 mciSendString(string command, StringBuilder buffer, int bufferSize, IntPtr hwndCallback);
Usage:
mciSendString(#"open path\to\your\file.wav type waveaudio alias anAliasForYourSound", null, 0, IntPtr.Zero);
mciSendString(#"play anAliasForYourSound", null, 0, IntPtr.Zero);
mciSendString(#"open path\to\your\anotherFile.wav type waveaudio alias anAliasForYourAnotherSound", null, 0, IntPtr.Zero);
mciSendString(#"play anAliasForYourAnotherSound", null, 0, IntPtr.Zero);
You can't start threads at exactly same time but in this case you can improve your code by loading the sounds before starting the threads:
static void Main(string[] args)
{
System.Media.SoundPlayer s1 = new System.Media.SoundPlayer(
#"c:\Users\Ben\Documents\c#\note_c.wav");
s1.Load();
System.Media.SoundPlayer s2 = new System.Media.SoundPlayer(
#"c:\Users\Ben\Documents\c#\note_e.wav");
s2.Load();
Console.WriteLine("Hello World");
Thread th = new Thread(() => playSound(s1));
Thread th1 = new Thread(() => playSound(s2));
th.Start();
th1.Start();
}
public static void playSound(System.Media.SoundPlayer s)
{
s.PlaySync();
}
Otherwise you'll need to implement a synchronization system.
The best way is to use DirectX xAudio2 via SharpDX , you can find it here:
https://github.com/sharpdx/SharpDX-Samples/tree/master/Desktop/XAudio2/PlaySound
It works perfectly , but it would be a bit tricky to make the code better, by utilizing Events & tasks instead of the while loop and sync execution, and to be able to load the xAudio2 graph dynamically to change the sound without reconstructing the whole graph.
Add these Nuget packages SharpDx
SharpDX.MediaFoundation
SharpDx.Xaudio2
and use code below, it uses DirectX xAudio2 and constructs a graph with a mixer, it can play WAV 8 and 16 as well
public class SoundServices : IDisposable
{
/// <summary>
/// Gets current sound file
/// </summary>
string SoundFile { get; }
/// <summary>
/// Gets current sound stream
/// </summary>
public Stream SoundStream { get; private set; }
/// <summary>
/// Gets/Sets looping option, sound will loop if set to true.
/// </summary>
public bool IsLooping { get; private set; }
/// <summary>
/// Holds the message of last error if any, check it if some feature fails
/// </summary>
public string LastErrorMsg { get; private set; }
//Play control flags
bool IsPlaying = false;
bool IsUserStop = false;
AutoResetEvent Playing;
float CurrentVolume = 1.0f;
bool IsInitialized = false;
SoundStream stream;
WaveFormat waveFormat;
AudioBuffer buffer;
SourceVoice sourceVoice;
XAudio2 xaudio2;
MasteringVoice masteringVoice;
/// <summary>
/// Initializes an instance by creating xAudio2 graph and preparing audio Buffers
/// </summary>
/// <param name="soundStream">WAV format sound stream</param>
/// <param name="loop">Bool indicating to loop sound playing or not</param>
public SoundServices(Stream soundStream, bool loop)
{
try
{
if (soundStream == null)
{
throw new ArgumentNullException("soundStream", "Null is not allowed, please specify a valid stream");
}
SoundStream = soundStream;
SoundFile = null;
IsLooping = loop;
//Playing = new ManualResetEvent(false);
Playing = new AutoResetEvent(false);
BuildxAudio2Graph();
}
catch (Exception e)
{
throw e;
}
}
#region Sound Play API
/// <summary>
/// Plays the sound stream loaded during initialization
/// </summary>
/// <returns>Task of sound playing</returns>
public Task PlaySound()
{
return Task.Factory.StartNew(() =>
{
PlayRepeatAsync();
});
}
/// <summary>
/// Task for starting play of sound buffers using xAudio2 graph
/// </summary>
void PlayRepeatAsync()
{
try
{
IsPlaying = true;
if (buffer == null)
{
//stream = new SoundStream(SoundStream);
//waveFormat = stream.Format;
buffer = new AudioBuffer
{
Stream = stream.ToDataStream(),
AudioBytes = (int)stream.Length,
Flags = SharpDX.XAudio2.BufferFlags.EndOfStream
};
if (IsLooping)
buffer.LoopCount = AudioBuffer.LoopInfinite;
sourceVoice.SubmitSourceBuffer(buffer, stream.DecodedPacketsInfo);
//Close the stream as it is now loaded in buffer already
//stream.Close();
}
sourceVoice.Start();
Playing.WaitOne();
sourceVoice.Stop();
IsPlaying = false;
sourceVoice.FlushSourceBuffers();
//xAudio2 graph creation step (5) send the AudioBuffer to sourceVoice
sourceVoice.SubmitSourceBuffer(buffer, stream.DecodedPacketsInfo);
}
catch (Exception e)
{
LastErrorMsg = "PlayRepeatAsync(): "+ e.Message;
IsPlaying = false;
}
}
/// <summary>
/// Initializes xAudio2 graph to be used for sound playing
/// </summary>
void BuildxAudio2Graph()
{
try
{
stream = new SoundStream(SoundStream);
waveFormat = stream.Format;
//xAudio2 graph creation step (1) Create XAudio2 device
xaudio2 = new XAudio2();
//xAudio2 graph creation step (2) Create MasteringVoice and connect it to device
//*Note: You must use aMasteringVoice to connect to xAudioDevice
masteringVoice = new MasteringVoice(xaudio2);
//SetVolume(CurrentVolume);
//xAudio2 graph creation step (3) Prepare sourceVoice
sourceVoice = new SourceVoice(xaudio2, waveFormat, true);
// Adds a callback check buffer end and Looping option
sourceVoice.BufferEnd += SourceVoice_BufferEnd;
//xAudio2 graph creation step (5) send the AudioBuffer to sourceVoice
IsInitialized = true;
}
catch (Exception e)
{
LastErrorMsg = "BuildxAudio2Graph(): " + e.Message;
IsInitialized = false;
}
}
/// <summary>
/// Recreates source buffer allowing sound change or loop change
/// </summary>
void RecreateBuffer()
{
try
{
SoundStream.Seek(0, SeekOrigin.Begin);
stream = new SoundStream(SoundStream);
waveFormat = stream.Format;
//if (buffer == null)
{
//stream = new SoundStream(SoundStream);
//waveFormat = stream.Format;
buffer = new AudioBuffer
{
Stream = stream.ToDataStream(),
AudioBytes = (int)stream.Length,
Flags = SharpDX.XAudio2.BufferFlags.EndOfStream
};
if (IsLooping)
buffer.LoopCount = AudioBuffer.LoopInfinite;
sourceVoice.FlushSourceBuffers();
sourceVoice.SubmitSourceBuffer(buffer, stream.DecodedPacketsInfo);
//Close the stream as it is now loaded in buffer already
//stream.Close();
}
}
catch (Exception e)
{
LastErrorMsg = "RecreateBuffer(): " + e.Message;
}
}
/// <summary>
/// Changes current audio to a new one
/// </summary>
/// <param name="soundStream">a stream from wav file</param>
public void ChangeSoundTo(Stream soundStream, bool Loop)
{
try
{
IsLooping = Loop;
SoundStream = soundStream;
stream = new SoundStream(SoundStream);
waveFormat = stream.Format;
sourceVoice = new SourceVoice(xaudio2, waveFormat, true);
sourceVoice.BufferEnd += SourceVoice_BufferEnd;
RecreateBuffer();
}
catch (Exception e)
{
IsInitialized = false;
LastErrorMsg = "ChangeSoundTo(): " + e.Message;
}
}
/// <summary>
/// Set loop ot no loop
/// </summary>
/// <param name="loop">True = Loop forever, false = play till end</param>
public void SetLooping(bool loop)
{
if (IsPlaying)
Stop();
IsLooping = loop;
RecreateBuffer();
}
#endregion
/// <summary>
/// Immediately Stops currently playing sound
/// </summary>
public void Stop()
{
try
{
if (IsPlaying)
{
IsUserStop = true;
Playing.Set();
}
}
catch (Exception e)
{
LastErrorMsg = "Stop(): " + e.Message;
}
}
/// <summary>
/// Gets Current Volume
/// </summary>
/// <returns>Current volume</returns>
public float GetVolume()
{
float current = 0.0f;
try
{
if (sourceVoice == null || sourceVoice.IsDisposed) return CurrentVolume;
sourceVoice.GetVolume(out current);
}
catch (Exception e)
{
LastErrorMsg = "GetVolume(): " + e.Message;
}
return current;
}
/// <summary>
/// Sets the current volume
/// </summary>
/// <param name="newVolume">returns back the current setting for confirmation</param>
/// <returns>The current set volume</returns>
public float SetVolume(float newVolume)
{
try
{
if (newVolume > 1 || newVolume < 0) return GetVolume();
if (sourceVoice == null || sourceVoice.IsDisposed)
{
CurrentVolume = newVolume;
return newVolume;
}
sourceVoice.SetVolume(newVolume, 0);
return GetVolume();
}
catch (Exception e)
{
LastErrorMsg = "SetVolume(): " + e.Message;
return 0.0f;
}
}
/// <summary>
/// End of buffer event handler
/// </summary>
/// <param name="obj"></param>
private void SourceVoice_BufferEnd(IntPtr obj)
{
//Debug.WriteLine($"buffer end reached with looping {IsLooping}");
if (!IsLooping)
{
if (IsPlaying && !IsUserStop)
Playing.Set();
else if(IsUserStop)
{
IsUserStop = false;
}
}
}
public void Dispose()
{
if (sourceVoice != null && !sourceVoice.IsDisposed)
{
sourceVoice.DestroyVoice();
sourceVoice.Dispose();
}
if (buffer != null && buffer.Stream != null)
buffer.Stream.Dispose();
if (masteringVoice != null && !masteringVoice.IsDisposed)
masteringVoice.Dispose();
if (xaudio2 != null && !xaudio2.IsDisposed)
xaudio2.Dispose();
}
~SoundServices()
{
if (sourceVoice != null && !sourceVoice.IsDisposed)
{
sourceVoice.DestroyVoice();
sourceVoice.Dispose();
}
if (buffer != null && buffer.Stream != null)
buffer.Stream.Dispose();
if (masteringVoice != null && !masteringVoice.IsDisposed)
masteringVoice.Dispose();
if (xaudio2 != null && !xaudio2.IsDisposed)
xaudio2.Dispose();
}
}
And you can use multiple SoundServices instances as you need:
var sp = new SoundServices(new MemoryStream(File.ReadAllBytes(WavFileName)), true);
if (sp != null)
sp.PlaySound();

Is System.Diagnostics.EventLog leaking memory?

When I run the following code :
static void Main(string[] args)
{
if (!System.Diagnostics.EventLog.SourceExists("eventSource"))
{
System.Diagnostics.EventLog.CreateEventSource("eventSource", "");
}
System.Diagnostics.EventLog eventLog = new System.Diagnostics.EventLog();
eventLog.Source = "eventSource";
eventLog.Log = "";
for (int i = 0; i < 10000; i++)
{
Thread.Sleep(100);
eventLog.WriteEntry("test", EventLogEntryType.Information);
//I also tried the static method, the program still leaks
//System.Diagnostics.EventLog.WriteEntry("eventSource", "test", EventLogEntryType.Information);
}
Console.ReadKey();
}
The memory usage starts around 1MB, but rise up very quickly and doesn't stop. Why ?
The code I'm using to install windows service with a designated event log:
[RunInstaller(true)]
public partial class SampleServiceInstaller : System.Configuration.Install.Installer
{
private string SampleServiceName = string.Empty;
private string SampleLogName = string.Empty;
public SampleServiceInstaller()
{
this.SampleServiceName = "SampleService";
this.SampleLogName = this.SampleServiceName + "Log";
ServiceProcessInstaller serviceProcessInstaller = new ServiceProcessInstaller();
serviceProcessInstaller.Password = null;
serviceProcessInstaller.Username = null;
serviceProcessInstaller.Account = ServiceAccount.LocalSystem;
ServiceInstaller serviceInstaller = new ServiceInstaller();
//This must be identical to the WindowsService.ServiceBase name
// set in the constructor of WindowsService.cs
serviceInstaller.ServiceName = this.SampleServiceName;
serviceInstaller.DisplayName = this.SampleServiceName;
serviceInstaller.StartType = ServiceStartMode.Automatic;
serviceInstaller.Description = "Sample Windows Service";
// kill the default event log installer
serviceInstaller.Installers.Clear();
// Create Event Source and Event Log    
// This recreates the log every time the service is reinstaled (old messages are lost)
if (EventLog.SourceExists(this.SampleServiceName)) EventLog.DeleteEventSource(this.SampleServiceName);
System.Diagnostics.EventLogInstaller logInstaller = new System.Diagnostics.EventLogInstaller();
logInstaller.Source = this.SampleServiceName; // use same as ServiceName
logInstaller.Log = this.SampleLogName; //can't be the same as service name
// Add all installers
this.Installers.AddRange(new Installer[] {
   serviceProcessInstaller, serviceInstaller, logInstaller
});
}
public override void Install(System.Collections.IDictionary savedState)
{
base.Install(savedState);
}
protected override void OnBeforeUninstall(System.Collections.IDictionary savedState)
{
base.OnBeforeUninstall(savedState);
}
service code:
public partial class SampleService : ServiceBase
{
/// <summary>
/// Designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Event log for the service
/// </summary>
EventLog serviceLog;
/// <summary>
/// Public Constructor for WindowsService.
/// - Initialization code here.
/// </summary>
public SampleService()
{
InitializeComponent();
}
/// <summary>
/// The Main Thread: list of services to run.
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new SampleService() };
ServiceBase.Run(ServicesToRun);
}
/// <summary>
/// Startup code
/// </summary>
/// <param name="args"></param>
protected override void OnStart(string[] args)
{
base.OnStart(args);
//
// run your own start code here
//
serviceLog.WriteEntry("My service started", EventLogEntryType.Information, 0);
}
/// <summary>
/// Stop code
/// </summary>
protected override void OnStop()
{
//
// run your own stop code here
//
serviceLog.WriteEntry("My service stopped", EventLogEntryType.Information, 0);
base.OnStop();
}
/// <summary>
/// Cleanup code
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing)
{
//
// do disposing here
//
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
/// <summary>
/// Pause code
/// </summary>
protected override void OnPause()
{
base.OnPause();
//
// code to run if service pauses
//
}
/// <summary>
/// Continue code
/// </summary>
protected override void OnContinue()
{
base.OnContinue();
//
// code tu run when service continues after being paused
//
}
/// <summary>
/// Called when the System is shutting down
/// - when special handling
/// of code that deals with a system shutdown, such
/// as saving special data before shutdown is needed.
/// </summary>
protected override void OnShutdown()
{
//
// code tu run when system is shut down
//
base.OnShutdown();
}
/// <summary>
/// If sending a command to the service is needed
/// without the need for Remoting or Sockets,
/// this method is used to do custom methods.
/// int command = 128; //Some Arbitrary number between 128 & 256
/// ServiceController sc = new ServiceController("NameOfService");
/// sc.ExecuteCommand(command);
/// </summary>
/// <param name="command">Arbitrary Integer between 128 & 256</param>
protected override void OnCustomCommand(int command)
{
base.OnCustomCommand(command);
//
// handle custom code here
//
}
/// <summary>
/// Useful for detecting power status changes,
/// such as going into Suspend mode or Low Battery for laptops.
/// </summary>
/// <param name="powerStatus">The Power Broadcast Status
/// (BatteryLow, Suspend, etc.)</param>
protected override bool OnPowerEvent(PowerBroadcastStatus powerStatus)
{
//
// handle power events here
//
return base.OnPowerEvent(powerStatus);
}
/// <summary>
/// To handle a change event
/// from a Terminal Server session.
/// Useful if determining
/// when a user logs in remotely or logs off,
/// or when someone logs into the console is needed.
/// </summary>
/// <param name="changeDescription">The Session Change
/// Event that occured.</param>
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
//
// handle session change here
//
base.OnSessionChange(changeDescription);
}
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
// first 8 letters should be unique
this.ServiceName = "SampleService";
// if you want to log service event to log registered while installing the service
string newLogName = this.ServiceName + "Log";
string newSourceName = this.ServiceName;
if (!EventLog.SourceExists(newSourceName))
{
EventLog.CreateEventSource(newSourceName, newLogName);
}
serviceLog = new EventLog();
serviceLog.Source = newSourceName;
serviceLog.Log = newLogName;
// Causes log to be disposed when the service is disposed
components.Add(serviceLog);
// Flags set whether or not to handle that specific type of event.
this.CanHandlePowerEvent = true;
this.CanHandleSessionChangeEvent = true;
this.CanPauseAndContinue = true;
this.CanShutdown = true;
this.CanStop = true;
}
}

how to create a text file in c# using visual studio?

I have been trying to add a Write text file section to this project but i keep getting told that lots of things 'dont exist in the current context'.
The text tile is meant to be created my documents showing 'First line,new line 1, new line 2'
This should work alongside the kinect sample.
I am sorry that i am very new to this and may be doing it completely wrong.
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MainWindow.xaml.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace Microsoft.Samples.Kinect.HDFaceBasics
{
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using Microsoft.Kinect;
using Microsoft.Kinect.Face;
using System.IO;
/// <summary>
/// Main Window
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged, IDisposable
{
// Create a string array with the lines of text
string text = "First line" + Environment.NewLine;
// Set a variable to the My Documents path.
string mydocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
// Write the text to a new file named "WriteFile.txt".
File.WriteAllText(mydocpath + #"\WriteFile.txt", text);
// Create a string array with the additional lines of text
string[] lines = { "New line 1", "New line 2" };
// Append new lines of text to the file
File.AppendAllLines(mydocpath + #"\WriteFile.txt", lines);
/// <summary>
/// Currently used KinectSensor
/// </summary>
private KinectSensor sensor = null;
/// <summary>
/// Body frame source to get a BodyFrameReader
/// </summary>
private BodyFrameSource bodySource = null;
/// <summary>
/// Body frame reader to get body frames
/// </summary>
private BodyFrameReader bodyReader = null;
/// <summary>
/// HighDefinitionFaceFrameSource to get a reader and a builder from.
/// Also to set the currently tracked user id to get High Definition Face Frames of
/// </summary>
private HighDefinitionFaceFrameSource highDefinitionFaceFrameSource = null;
/// <summary>
/// HighDefinitionFaceFrameReader to read HighDefinitionFaceFrame to get FaceAlignment
/// </summary>
private HighDefinitionFaceFrameReader highDefinitionFaceFrameReader = null;
/// <summary>
/// FaceAlignment is the result of tracking a face, it has face animations location and orientation
/// </summary>
private FaceAlignment currentFaceAlignment = null;
/// <summary>
/// FaceModel is a result of capturing a face
/// </summary>
private FaceModel currentFaceModel = null;
/// <summary>
/// FaceModelBuilder is used to produce a FaceModel
/// </summary>
private FaceModelBuilder faceModelBuilder = null;
/// <summary>
/// The currently tracked body
/// </summary>
private Body currentTrackedBody = null;
/// <summary>
/// The currently tracked body
/// </summary>
private ulong currentTrackingId = 0;
/// <summary>
/// Gets or sets the current tracked user id
/// </summary>
private string currentBuilderStatus = string.Empty;
/// <summary>
/// Gets or sets the current status text to display
/// </summary>
private string statusText = "Ready To Start Capture";
/// <summary>
/// Initializes a new instance of the MainWindow class.
/// </summary>
public MainWindow()
{
this.InitializeComponent();
this.DataContext = this;
}
/// <summary>
/// INotifyPropertyChangedPropertyChanged event to allow window controls to bind to changeable data
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Gets or sets the current status text to display
/// </summary>
public string StatusText
{
get
{
return this.statusText;
}
set
{
if (this.statusText != value)
{
this.statusText = value;
// notify any bound elements that the text has changed
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs("StatusText"));
}
}
}
}
/// <summary>
/// Gets or sets the current tracked user id
/// </summary>
private ulong CurrentTrackingId
{
get
{
return this.currentTrackingId;
}
set
{
this.currentTrackingId = value;
this.StatusText = this.MakeStatusText();
}
}
/// <summary>
/// Gets or sets the current Face Builder instructions to user
/// </summary>
private string CurrentBuilderStatus
{
get
{
return this.currentBuilderStatus;
}
set
{
this.currentBuilderStatus = value;
this.StatusText = this.MakeStatusText();
}
}
/// <summary>
/// Called when disposed of
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose based on whether or not managed or native resources should be freed
/// </summary>
/// <param name="disposing">Set to true to free both native and managed resources, false otherwise</param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (this.currentFaceModel != null)
{
this.currentFaceModel.Dispose();
this.currentFaceModel = null;
}
}
}
/// <summary>
/// Returns the length of a vector from origin
/// </summary>
/// <param name="point">Point in space to find it's distance from origin</param>
/// <returns>Distance from origin</returns>
private static double VectorLength(CameraSpacePoint point)
{
var result = Math.Pow(point.X, 2) + Math.Pow(point.Y, 2) + Math.Pow(point.Z, 2);
result = Math.Sqrt(result);
return result;
}
/// <summary>
/// Finds the closest body from the sensor if any
/// </summary>
/// <param name="bodyFrame">A body frame</param>
/// <returns>Closest body, null of none</returns>
private static Body FindClosestBody(BodyFrame bodyFrame)
{
Body result = null;
double closestBodyDistance = double.MaxValue;
Body[] bodies = new Body[bodyFrame.BodyCount];
bodyFrame.GetAndRefreshBodyData(bodies);
foreach (var body in bodies)
{
if (body.IsTracked)
{
var currentLocation = body.Joints[JointType.SpineBase].Position;
var currentDistance = VectorLength(currentLocation);
if (result == null || currentDistance < closestBodyDistance)
{
result = body;
closestBodyDistance = currentDistance;
}
}
}
return result;
}
/// <summary>
/// Find if there is a body tracked with the given trackingId
/// </summary>
/// <param name="bodyFrame">A body frame</param>
/// <param name="trackingId">The tracking Id</param>
/// <returns>The body object, null of none</returns>
private static Body FindBodyWithTrackingId(BodyFrame bodyFrame, ulong trackingId)
{
Body result = null;
Body[] bodies = new Body[bodyFrame.BodyCount];
bodyFrame.GetAndRefreshBodyData(bodies);
foreach (var body in bodies)
{
if (body.IsTracked)
{
if (body.TrackingId == trackingId)
{
result = body;
break;
}
}
}
return result;
}
/// <summary>
/// Gets the current collection status
/// </summary>
/// <param name="status">Status value</param>
/// <returns>Status value as text</returns>
private static string GetCollectionStatusText(FaceModelBuilderCollectionStatus status)
{
string res = string.Empty;
if ((status & FaceModelBuilderCollectionStatus.FrontViewFramesNeeded) != 0)
{
res = "FrontViewFramesNeeded";
return res;
}
if ((status & FaceModelBuilderCollectionStatus.LeftViewsNeeded) != 0)
{
res = "LeftViewsNeeded";
return res;
}
if ((status & FaceModelBuilderCollectionStatus.RightViewsNeeded) != 0)
{
res = "RightViewsNeeded";
return res;
}
if ((status & FaceModelBuilderCollectionStatus.TiltedUpViewsNeeded) != 0)
{
res = "TiltedUpViewsNeeded";
return res;
}
if ((status & FaceModelBuilderCollectionStatus.Complete) != 0)
{
res = "Complete";
return res;
}
if ((status & FaceModelBuilderCollectionStatus.MoreFramesNeeded) != 0)
{
res = "TiltedUpViewsNeeded";
return res;
}
return res;
}
/// <summary>
/// Helper function to format a status message
/// </summary>
/// <returns>Status text</returns>
private string MakeStatusText()
{
string status = string.Format(System.Globalization.CultureInfo.CurrentCulture, "Builder Status: {0}, Current Tracking ID: {1}", this.CurrentBuilderStatus, this.CurrentTrackingId);
return status;
}
/// <summary>
/// Fires when Window is Loaded
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.InitializeHDFace();
}
/// <summary>
/// Initialize Kinect object
/// </summary>
private void InitializeHDFace()
{
this.CurrentBuilderStatus = "Ready To Start Capture";
this.sensor = KinectSensor.GetDefault();
this.bodySource = this.sensor.BodyFrameSource;
this.bodyReader = this.bodySource.OpenReader();
this.bodyReader.FrameArrived += this.BodyReader_FrameArrived;
this.highDefinitionFaceFrameSource = new HighDefinitionFaceFrameSource(this.sensor);
this.highDefinitionFaceFrameSource.TrackingIdLost += this.HdFaceSource_TrackingIdLost;
this.highDefinitionFaceFrameReader = this.highDefinitionFaceFrameSource.OpenReader();
this.highDefinitionFaceFrameReader.FrameArrived += this.HdFaceReader_FrameArrived;
this.currentFaceModel = new FaceModel();
this.currentFaceAlignment = new FaceAlignment();
this.InitializeMesh();
this.UpdateMesh();
this.sensor.Open();
}
/// <summary>
/// Initializes a 3D mesh to deform every frame
/// </summary>
private void InitializeMesh()
{
var vertices = this.currentFaceModel.CalculateVerticesForAlignment(this.currentFaceAlignment);
var triangleIndices = this.currentFaceModel.TriangleIndices;
var indices = new Int32Collection(triangleIndices.Count);
for (int i = 0; i < triangleIndices.Count; i += 3)
{
uint index01 = triangleIndices[i];
uint index02 = triangleIndices[i + 1];
uint index03 = triangleIndices[i + 2];
indices.Add((int)index03);
indices.Add((int)index02);
indices.Add((int)index01);
}
this.theGeometry.TriangleIndices = indices;
this.theGeometry.Normals = null;
this.theGeometry.Positions = new Point3DCollection();
this.theGeometry.TextureCoordinates = new PointCollection();
foreach (var vert in vertices)
{
this.theGeometry.Positions.Add(new Point3D(vert.X, vert.Y, -vert.Z));
this.theGeometry.TextureCoordinates.Add(new Point());
}
}
/// <summary>
/// Sends the new deformed mesh to be drawn
/// </summary>
private void UpdateMesh()
{
var vertices = this.currentFaceModel.CalculateVerticesForAlignment(this.currentFaceAlignment);
for (int i = 0; i < vertices.Count; i++)
{
var vert = vertices[i];
this.theGeometry.Positions[i] = new Point3D(vert.X, vert.Y, -vert.Z);
}
}
/// <summary>
/// Start a face capture on clicking the button
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void StartCapture_Button_Click(object sender, RoutedEventArgs e)
{
this.StartCapture();
}
/// <summary>
/// This event fires when a BodyFrame is ready for consumption
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void BodyReader_FrameArrived(object sender, BodyFrameArrivedEventArgs e)
{
this.CheckOnBuilderStatus();
var frameReference = e.FrameReference;
using (var frame = frameReference.AcquireFrame())
{
if (frame == null)
{
// We might miss the chance to acquire the frame, it will be null if it's missed
return;
}
if (this.currentTrackedBody != null)
{
this.currentTrackedBody = FindBodyWithTrackingId(frame, this.CurrentTrackingId);
if (this.currentTrackedBody != null)
{
return;
}
}
Body selectedBody = FindClosestBody(frame);
if (selectedBody == null)
{
return;
}
this.currentTrackedBody = selectedBody;
this.CurrentTrackingId = selectedBody.TrackingId;
this.highDefinitionFaceFrameSource.TrackingId = this.CurrentTrackingId;
}
}
/// <summary>
/// This event is fired when a tracking is lost for a body tracked by HDFace Tracker
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void HdFaceSource_TrackingIdLost(object sender, TrackingIdLostEventArgs e)
{
var lostTrackingID = e.TrackingId;
if (this.CurrentTrackingId == lostTrackingID)
{
this.CurrentTrackingId = 0;
this.currentTrackedBody = null;
if (this.faceModelBuilder != null)
{
this.faceModelBuilder.Dispose();
this.faceModelBuilder = null;
}
this.highDefinitionFaceFrameSource.TrackingId = 0;
}
}
/// <summary>
/// This event is fired when a new HDFace frame is ready for consumption
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void HdFaceReader_FrameArrived(object sender, HighDefinitionFaceFrameArrivedEventArgs e)
{
using (var frame = e.FrameReference.AcquireFrame())
{
// We might miss the chance to acquire the frame; it will be null if it's missed.
// Also ignore this frame if face tracking failed.
if (frame == null || !frame.IsFaceTracked)
{
return;
}
frame.GetAndRefreshFaceAlignmentResult(this.currentFaceAlignment);
this.UpdateMesh();
}
}
/// <summary>
/// Start a face capture operation
/// </summary>
private void StartCapture()
{
this.StopFaceCapture();
this.faceModelBuilder = null;
this.faceModelBuilder = this.highDefinitionFaceFrameSource.OpenModelBuilder(FaceModelBuilderAttributes.None);
this.faceModelBuilder.BeginFaceDataCollection();
this.faceModelBuilder.CollectionCompleted += this.HdFaceBuilder_CollectionCompleted;
}
/// <summary>
/// Cancel the current face capture operation
/// </summary>
private void StopFaceCapture()
{
if (this.faceModelBuilder != null)
{
this.faceModelBuilder.Dispose();
this.faceModelBuilder = null;
}
}
/// <summary>
/// This event fires when the face capture operation is completed
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void HdFaceBuilder_CollectionCompleted(object sender, FaceModelBuilderCollectionCompletedEventArgs e)
{
var modelData = e.ModelData;
this.currentFaceModel = modelData.ProduceFaceModel();
this.faceModelBuilder.Dispose();
this.faceModelBuilder = null;
this.CurrentBuilderStatus = "Capture Complete";
}
/// <summary>
/// Check the face model builder status
/// </summary>
private void CheckOnBuilderStatus()
{
if (this.faceModelBuilder == null)
{
return;
}
string newStatus = string.Empty;
var captureStatus = this.faceModelBuilder.CaptureStatus;
newStatus += captureStatus.ToString();
var collectionStatus = this.faceModelBuilder.CollectionStatus;
newStatus += ", " + GetCollectionStatusText(collectionStatus);
this.CurrentBuilderStatus = newStatus;
}
}
}
create a method that you can call that will allow you to create as well as append to the file
private static void WriteAndOrAppendText(string path, string strText)
{
using (StreamWriter fileStream = new StreamWriter(path, true))
{
fileStream.WriteLine(strText);
fileStream.Flush();
fileStream.Close();
}
}
// Set a variable to the My Documents path.
string mydocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
// Write the text to a new file named "WriteFile.txt".
WriteAndOrAppendText(mydocpath + #"\WriteFile.txt", text);
string[] lines = { "New line 1", "New line 2" };
WriteAndOrAppendText(mydocpath , string.Join(",", lines.ToArray()));

Restarting an app as administrator that uses mutex

I have an application that uses a mutex to stop multiple instances running at the same time, and to accept command line inputs in to the running instance.
I have a function in the app that asks the user if they want to restart as admin when required. For example the features they have enabled might require admin rights.
The mutex class looks like this:
namespace SingleInstanceClassLibrary
{
/// <summary>
/// Enforces single instance for an application.
/// </summary>
public class SingleInstance : IDisposable
{
private Mutex mutex = null;
private Boolean ownsMutex = false;
private Guid identifier = Guid.Empty;
/// <summary>
/// Enforces single instance for an application.
/// </summary>
/// <param name="identifier">An identifier unique to this application. </param>
public SingleInstance(Guid identifier)
{
this.identifier = identifier;
mutex = new Mutex(true, identifier.ToString(), out ownsMutex);
}
/// <summary>
/// Indicates whether this is the first instance of this application.
/// </summary>
public Boolean IsFirstInstance
{ get { return ownsMutex; } }
/// <summary>
/// Passes the given arguments to the first running instance of the application.
/// </summary>
/// <param name="arguments">The arguments to pass.</param>
/// <returns>Return true if the operation succeded, false otherwise. </returns>
public Boolean PassArgumentsToFirstInstance(String[] arguments)
{
if (IsFirstInstance)
throw new InvalidOperationException("This is the first instance.");
try
{
using (NamedPipeClientStream client = new NamedPipeClientStream(identifier.ToString()))
using (StreamWriter writer = new StreamWriter(client))
{
client.Connect(200);
foreach (String argument in arguments)
writer.WriteLine(argument);
}
return true;
}
catch (TimeoutException)
{ } //Couldn't connect to server
catch (IOException)
{ } //Pipe was broken
return false;
}
/// <summary>
/// Listens for arguments being passed from successive instances of the applicaiton.
/// </summary>
public void ListenForArgumentsFromSuccessiveInstances()
{
if (!IsFirstInstance)
throw new InvalidOperationException("This is not the first instance.");
ThreadPool.QueueUserWorkItem(new WaitCallback(ListenForArguments));
}
/// <summary>
/// Listens for arguments on a named pipe.
/// </summary>
/// <param name="state">State object required by WaitCallback delegate.</param>
private void ListenForArguments(Object state)
{
try
{
using (NamedPipeServerStream server = new NamedPipeServerStream(identifier.ToString()))
using (StreamReader reader = new StreamReader(server))
{
server.WaitForConnection();
List<String> arguments = new List<String>();
while (server.IsConnected)
arguments.Add(reader.ReadLine());
ThreadPool.QueueUserWorkItem(new WaitCallback(CallOnArgumentsReceived), arguments.ToArray());
}
}
catch (IOException)
{ } //Pipe was broken
finally
{
ListenForArguments(null);
}
}
/// <summary>
/// Calls the OnArgumentsReceived method casting the state Object to String[].
/// </summary>
/// <param name="state">The arguments to pass.</param>
private void CallOnArgumentsReceived(Object state)
{
OnArgumentsReceived((String[])state);
}
/// <summary>
/// Event raised when arguments are received from successive instances.
/// </summary>
public event EventHandler<ArgumentsReceivedEventArgs> ArgumentsReceived;
/// <summary>
/// Fires the ArgumentsReceived event.
/// </summary>
/// <param name="arguments">The arguments to pass with the ArgumentsReceivedEventArgs.</param>
private void OnArgumentsReceived(String[] arguments)
{
if (ArgumentsReceived != null)
ArgumentsReceived(this, new ArgumentsReceivedEventArgs() { Args = arguments });
}
#region IDisposable
private Boolean disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (mutex != null && ownsMutex)
{
mutex.ReleaseMutex();
mutex = null;
}
disposed = true;
}
}
~SingleInstance()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
I call it like this:
private static void Main()
{
Guid guid = new Guid("{6EAE2E61-E7EE-42bf-8EBE-BAB890C5410F}");
//SingleInstance ensures only 1 instance of the app runs at one time. If another instance is started
//it will be closed. If the 2nd instance included arguments these will be passed to
//the singleInstance_ArgumentsReceived event for originally running process
using (SingleInstance singleInstance = new SingleInstance(guid))
{
//MessageBox.Show(Environment.GetCommandLineArgs().ToString());
//if (Environment.GetCommandLineArgs().Contains("RunAsAdmin"))
//MessageBox.Show("YES");
if (singleInstance.IsFirstInstance || Environment.GetCommandLineArgs().Contains("RunAsAdmin"))
{
singleInstance.ArgumentsReceived += singleInstance_ArgumentsReceived;
singleInstance.ListenForArgumentsFromSuccessiveInstances();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Show the system tray icon.
//using (ProcessIcon pi = new ProcessIcon())
using (ProcessIcon pi = new ProcessIcon())
{
//Use to pass instance of ProcessIcon to LyncPresenceSwitcher
lyncPresenceSwitcher.processIcon = pi;
//Pass Lync instance
pi.lync = lyncClientController;
pi.Display();
// Make sure the application runs!
Application.Run();
}
}
else
singleInstance.PassArgumentsToFirstInstance(Environment.GetCommandLineArgs());
}
}
//Process arguments past with app execution
private static void singleInstance_ArgumentsReceived(object sender, ArgumentsReceivedEventArgs e)
{
if (settingsBox == null)
return;
foreach (String arg in e.Args)
{
//if arguments include OpenSettings open SettingsBox
if (arg == "OpenSettings")
{
settingsBox.ShowDialog();
}
if (arg == "RunAsAdmin")
{
//singleInstance.Dispose();
}
}
}
The app checks whether settings require admin access and prompts user to restart as admin when required. To restart the app I run this:
if (!IsRunAsAdmin())
{
// Launch itself as administrator
ProcessStartInfo proc = new ProcessStartInfo();
proc.UseShellExecute = true;
proc.WorkingDirectory = Environment.CurrentDirectory;
proc.FileName = Application.ExecutablePath;
proc.Verb = "runas";
proc.Arguments = "RunAsAdmin";
try
{
Process.Start(proc);
System.Environment.Exit(2);
return true;
}
catch
{
// The user refused the elevation.
// Do nothing and return directly ...
return false;
}
The problem is a new instance starts but is closed because of the mutex. Then when I close the original instance I get this:
So I was thinking I could pass an argument to the running instance to tell it to allow a new one to spawn, then close the original. Trouble is I cant figure out how to make this work.
Any help would be very much appreciated :)
p.s. I am a C# novice
Thanks!
The solution is to simply destroy your mutex prior to restarting your application:
mutex.Dispose();

WatiN unreliable for repeated downloads?

WatiN seems to not handle repeated download dialogs consistently:
foreach (string file in lstFiles)
{
// continue if no download link
if (!ie.Element([search criteria]).Exists) continue;
var btnDownload = ie.Element([search criteria]);
string fullFilename = workingDir + "\\" + file;
FileDownloadHandler download = new FileDownloadHandler(fullFilename);
using (new UseDialogOnce(ie.DialogWatcher, download))
{
btnDownload.ClickNoWait();
download.WaitUntilFileDownloadDialogIsHandled(30);
download.WaitUntilDownloadCompleted(150);
ie.RemoveDialogHandler(download);
}
}
Basically, I loop through a list of filenames that I expect to be available and click the download button. This usually works, but after so many downloads (it varies, sometimes everything that's available downloads, sometimes nothing) it will hang while waiting to handle the dialog. The button's identified correctly, the download dialog appears, it just isn't detected and handled. It isn't site-specific as similar methods on other sites are also met with variable success. Anyone encounter this before and know of a resolution?
edit: Repeated downloads do not work whatsoever in Server 2008. In Win7, this happens randomly after one or more successful repeated downloads.
The problem appears because IE File Download Dialog consist of 2 windows. WatiN DialogWatcher gets all the system windows and tries to handle them in foreach loop. After handling first correct dialog window DialogWatcher gets the next window wich has the same properties and is a valid Download Dialog. DialogWatcher starts waiting until this window is visible but it closes immediately after previos window is handled.
My solution is to return from foreach loop after any dialog is handled:
#region WatiN Copyright (C) 2006-2011 Jeroen van Menen
//Copyright 2006-2011 Jeroen van Menen
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion Copyright
using System;
using System.Collections.Generic;
using System.Threading;
using WatiN.Core.Exceptions;
using WatiN.Core.Interfaces;
using WatiN.Core.Logging;
using WatiN.Core.Native.InternetExplorer;
using WatiN.Core.Native.Windows;
using WatiN.Core.UtilityClasses;
namespace WatiN.Core.DialogHandlers
{
/// <summary>
/// This class handles alert/popup dialogs. Every second it checks if a dialog
/// is shown. If so, it stores it's message in the alertQueue and closses the dialog
/// by clicking the close button in the title bar.
/// </summary>
public class DialogWatcher : IDisposable
{
private static IList<DialogWatcher> dialogWatchers = new List<DialogWatcher>();
private bool _keepRunning = true;
private readonly IList<IDialogHandler> _handlers;
private readonly Thread _watcherThread;
private bool _closeUnhandledDialogs = Settings.AutoCloseDialogs;
public Window MainWindow { get; private set; }
/// <summary>
/// Gets the dialog watcher for the specified (main) internet explorer window.
/// It creates new instance if no dialog watcher for the specified window exists.
/// </summary>
/// <param name="mainWindowHwnd">The (main) internet explorer window.</param>
/// <returns></returns>
public static DialogWatcher GetDialogWatcher(IntPtr mainWindowHwnd)
{
var window = new Window(mainWindowHwnd);
Logger.LogDebug("GetDialogWatcher mainhwnd: " + window.Hwnd + ", " + window.Title);
var toplevelWindow = window.ToplevelWindow;
Logger.LogDebug("GetDialogWatcher mainhwnd: " + toplevelWindow.Hwnd + ", " + toplevelWindow.Title);
CleanupDialogWatcherCache();
var dialogWatcher = GetDialogWatcherFromCache(toplevelWindow);
// If no dialogwatcher exists for the ieprocessid then
// create a new one, store it and return it.
if (dialogWatcher == null)
{
dialogWatcher = new DialogWatcher(toplevelWindow);
dialogWatchers.Add(dialogWatcher);
}
return dialogWatcher;
}
public static DialogWatcher GetDialogWatcherFromCache(Window mainWindow)
{
// Loop through already created dialogwatchers and
// return a dialogWatcher if one exists for the given processid
foreach (var dialogWatcher in dialogWatchers)
{
if (dialogWatcher.MainWindow.Equals(mainWindow))
{
return dialogWatcher;
}
}
return null;
}
public static void CleanupDialogWatcherCache()
{
var cleanedupDialogWatcherCache = new List<DialogWatcher>();
foreach (var dialogWatcher in dialogWatchers)
{
if (!dialogWatcher.IsRunning)
{
dialogWatcher.Dispose();
}
else
{
cleanedupDialogWatcherCache.Add(dialogWatcher);
}
}
dialogWatchers = cleanedupDialogWatcherCache;
}
/// <summary>
/// Initializes a new instance of the <see cref="DialogWatcher"/> class.
/// You are encouraged to use the Factory method <see cref="DialogWatcher.GetDialogWatcherFromCache"/>
/// instead.
/// </summary>
/// <param name="mainWindow">The main window handle of internet explorer.</param>
public DialogWatcher(Window mainWindow)
{
MainWindow = mainWindow;
_handlers = new List<IDialogHandler>();
// Create thread to watch windows
_watcherThread = new Thread(Start);
// Start the thread.
_watcherThread.Start();
}
/// <summary>
/// Increases the reference count of this DialogWatcher instance with 1.
/// </summary>
public void IncreaseReferenceCount()
{
ReferenceCount++;
}
/// <summary>
/// Decreases the reference count of this DialogWatcher instance with 1.
/// When reference count becomes zero, the Dispose method will be
/// automatically called. This method will throw an <see cref="ReferenceCountException"/>
/// if the reference count is zero.
/// </summary>
public void DecreaseReferenceCount()
{
if (ReferenceCount > 0)
{
ReferenceCount--;
}
else
{
throw new ReferenceCountException();
}
if (ReferenceCount == 0)
{
Dispose();
}
}
/// <summary>
/// Adds the specified handler.
/// </summary>
/// <param name="handler">The handler.</param>
public void Add(IDialogHandler handler)
{
lock (this)
{
_handlers.Add(handler);
}
}
/// <summary>
/// Removes the specified handler.
/// </summary>
/// <param name="handler">The handler.</param>
public void Remove(IDialogHandler handler)
{
lock (this)
{
_handlers.Remove(handler);
}
}
/// <summary>
/// Removes all instances that match <paramref name="handler"/>.
/// This method determines equality by calling Object.Equals.
/// </summary>
/// <param name="handler">The object implementing IDialogHandler.</param>
/// <example>
/// If you want to use RemoveAll with your custom dialog handler to
/// remove all instances of your dialog handler from a DialogWatcher instance,
/// you should override the Equals method in your custom dialog handler class
/// like this:
/// <code>
/// public override bool Equals(object obj)
/// {
/// if (obj == null) return false;
///
/// return (obj is YourDialogHandlerClassNameGoesHere);
/// }
/// </code>
/// You could also inherit from <see cref="BaseDialogHandler"/> instead of implementing
/// <see cref="IDialogHandler"/> in your custom dialog handler. <see cref="BaseDialogHandler"/> provides
/// overrides for Equals and GetHashCode that work with RemoveAll.
/// </example>
public void RemoveAll(IDialogHandler handler)
{
while (Contains(handler))
{
Remove(handler);
}
}
/// <summary>
/// Removes all registered dialog handlers.
/// </summary>
public void Clear()
{
lock (this)
{
_handlers.Clear();
}
}
/// <summary>
/// Determines whether this <see cref="DialogWatcher"/> contains the specified dialog handler.
/// </summary>
/// <param name="handler">The dialog handler.</param>
/// <returns>
/// <c>true</c> if [contains] [the specified handler]; otherwise, <c>false</c>.
/// </returns>
public bool Contains(IDialogHandler handler)
{
lock (this)
{
return _handlers.Contains(handler);
}
}
/// <summary>
/// Gets the count of registered dialog handlers.
/// </summary>
/// <value>The count.</value>
public int Count
{
get
{
lock (this)
{
return _handlers.Count;
}
}
}
/// <summary>
/// Gets or sets a value indicating whether unhandled dialogs should be closed automaticaly.
/// The initial value is set to the value of <cref name="Settings.AutoCloseDialogs" />.
/// </summary>
/// <value>
/// <c>true</c> if unhandled dialogs should be closed automaticaly; otherwise, <c>false</c>.
/// </value>
public bool CloseUnhandledDialogs
{
get
{
lock (this)
{
return _closeUnhandledDialogs;
}
}
set
{
lock (this)
{
_closeUnhandledDialogs = value;
}
}
}
/// <summary>
/// Gets the (main) internet explorer window handle this dialog watcher watches.
/// </summary>
/// <value>The process id.</value>
public IntPtr MainWindowHwnd
{
get { return MainWindow.Hwnd; }
}
/// <summary>
/// Called by the constructor to start watching popups
/// on a separate thread.
/// </summary>
private void Start()
{
while (_keepRunning)
{
if (MainWindow.Exists())
{
var winEnumerator = new WindowsEnumerator();
var windows = winEnumerator.GetWindows(win => true);
foreach (var window in windows)
{
if (!_keepRunning) return;
if(HandleWindow(window))
break;
}
// Keep DialogWatcher responsive during 1 second sleep period
var count = 0;
while (_keepRunning && count < 5)
{
Thread.Sleep(200);
count++;
}
}
else
{
_keepRunning = false;
}
}
}
public bool IsRunning
{
get { return _watcherThread.IsAlive; }
}
public int ReferenceCount { get; private set; }
/// <summary>
/// Get the last stored exception thrown by a dialog handler while
/// calling the <see cref="IDialogHandler.HandleDialog"/> method of the
/// dialog handler.
/// </summary>
/// <value>The last exception.</value>
public Exception LastException { get; private set; }
/// <summary>
/// If the window is a dialog and visible, it will be passed to
/// the registered dialog handlers. I none if these can handle
/// it, it will be closed if <see cref="CloseUnhandledDialogs"/>
/// is <c>true</c>.
/// </summary>
/// <param name="window">The window.</param>
/// <returns>
/// <c>true</c> if dialog is handled by one of handlers; otherwise, <c>false</c>.
/// </returns>
public bool HandleWindow(Window window)
{
if (!window.IsDialog()) return false;
if (!HasDialogSameProcessNameAsBrowserWindow(window)) return false;
// This is needed otherwise the window Style will return a "wrong" result.
WaitUntilVisibleOrTimeOut(window);
// Lock the thread and see if a handler will handle
// this dialog window
lock (this)
{
foreach (var dialogHandler in _handlers)
{
try
{
if (dialogHandler.CanHandleDialog(window, MainWindow.Hwnd))
{
if (dialogHandler.HandleDialog(window)) return true;
}
}
catch (Exception e)
{
LastException = e;
Logger.LogAction((LogFunction log) => { log("Exception was thrown while DialogWatcher called HandleDialog: {0}",e.ToString()); });
}
}
// If no handler handled the dialog, see if the dialog
// should be closed automatically.
if (!CloseUnhandledDialogs || !MainWindow.Equals(window.ToplevelWindow)) return false;
Logger.LogAction((LogFunction log) => { log("Auto closing dialog with title: '{0}', text: {1}, style: ", window.Title, window.Message, window.StyleInHex); });
window.ForceClose();
}
return false;
}
private bool HasDialogSameProcessNameAsBrowserWindow(Window window)
{
var comparer = new Comparers.StringComparer(window.ProcessName, true);
return comparer.Compare(MainWindow.ProcessName);
}
private static void WaitUntilVisibleOrTimeOut(Window window)
{
// Wait untill window is visible so all properties
// of the window class (like Style and StyleInHex)
// will return valid values.
var tryActionUntilTimeOut = new TryFuncUntilTimeOut(TimeSpan.FromSeconds(Settings.WaitForCompleteTimeOut));
var success = tryActionUntilTimeOut.Try(() => window.Visible);
if (!success)
{
Logger.LogAction((LogFunction log) => { log("Dialog with title '{0}' not visible after {1} seconds.", window.Title, Settings.WaitForCompleteTimeOut); });
}
}
#region IDisposable Members
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or
/// resetting unmanaged resources.
/// </summary>
public void Dispose()
{
lock (this)
{
_keepRunning = false;
}
if (IsRunning)
{
_watcherThread.Join();
}
Clear();
}
#endregion
}
}
My team ran into this as well while automating IE8 with WatiN. The problem seems to be with IE, possibly doing some time consuming house-cleaning. The work-around we ultimately used was to invoke a new instance of IE within the outer loop, disposing of it each iteration and then waiting for 5 seconds for whatever was going on in the background to resolve. It was a hack but got the job done.
foreach (var file in lstFiles)
{
string fullFilename = workingDir + "\\" + file;
using (var browser = new IE(fullFilename))
{
//page manipulations...
FileDownloadHandler download = new FileDownloadHandler(fullFilename);
using (new UseDialogOnce(browser.DialogWatcher, download))
{ //lnkFile.ClickNoWait();
download.WaitUntilFileDownloadDialogIsHandled(15);
download.WaitUntilDownloadCompleted(150);
}
}
Thread.Sleep(5000);
}

Categories