How to trigger/run events when using SpVoice/SpFileStream in C# - c#

I am using SpVoice to generate audio files, using SpFileStream.
I need several information about the text to be spooken, f.ex word boundaries.
I try to add some events to execute when end of word occurs.
But the eventHandler does not run as expected.
I have tried to do as specified here SpVoice (Events) Interface (SAPI 5.3)
The code:
public void SpeakToFile(String toSpeak, string id)
{
SpVoice voiceNew = new SpVoice();
voiceNew.EventInterests = SpeechVoiceEvents.SVEWordBoundary;
voiceNew.Word +=VoiceNewOnWord;
SpFileStream outStream = new SpFileStream();
string wavPath = _fileHelper.GetTempFileNameWav(id);
outStream.Open(wavPath, SpeechStreamFileMode.SSFMCreateForWrite, DoEvents:true);
voiceNew.AudioOutputStream = outStream;
voiceNew.Speak(toSpeak);
outStream.Close();
}
private void VoiceNewOnWord(int streamNumber, object streamPosition, int characterPosition, int length)
{
Boundary boundary = new Boundary();
boundary.StreamPosition = streamPosition.ConvertTo<long>();
boundary.CharacterPosition = characterPosition;
boundary.Length = length;
log.Info("word_boundary2: - strPos : " + boundary.StreamPosition + " - charPos : " + boundary.CharacterPosition + " - length : " + boundary.Length);
}
Anyone?

Related

How to print only datalabel out of whole scandata?

I am a new bee to C# programming. I have a zebra bar code scanner. I made a C# code according to the software user manual. I am able to print the scandata. However this data consist of all the information about the scanner. It has serial number,module number,GUID,datatype and datalabel.
This datalabel is the information about the bar code. I am interested in this datalabel only. I need to develop further code using this datalabel.
How can I print only the datalabel?.
Here I am attaching my code. Thank you.
namespace ConsoleApp_scandata
{
class Program
{
//declare the core scanner class
static CCoreScannerClass cCoreScannerClass;
static void Main(string[] args)
{
cCoreScannerClass = new CoreScanner.CCoreScannerClass();
//CALL OPEN API
short[] scannerTypes = new short[1]; //scanner types intrested in
scannerTypes[0] = 1; // set all scanner types to 1
short numberOfScannerTypes = 1; // size of the scanner type array
int status; // Extend API return code
cCoreScannerClass.Open(0, scannerTypes, numberOfScannerTypes, out status);
if (status == 0)
Console.WriteLine("CoreScanner API OPEN");
else
Console.WriteLine("CoreScanner API CLOSED");
// Lists all scanners connected to the host computer.
// will return nothing
short numberOfScanners;
int[] connectedScannerIDList = new int[255];
string outXML;
cCoreScannerClass.GetScanners(out numberOfScanners, connectedScannerIDList, out outXML, out status);
//below does not work because string is an xml file and is never NULL
Console.WriteLine(outXML);
// Console.WriteLine(outXML.ToString());
cCoreScannerClass.BarcodeEvent += new _ICoreScannerEvents_BarcodeEventEventHandler(OnBarcodeEvent);
int opcode = 1001;
string inXML = "<inArgs>" +
"<cmdArgs>" +
"<arg-int>1</arg-int>" +
"<arg-int>1</arg-int>" +
"</cmdArgs>" +
"</inArgs>";
cCoreScannerClass.ExecCommand(opcode, ref inXML, out outXML, out status);
opcode = 2011;
inXML = "<inArgs>" +
"<scannerID>1</scannerID>" +
"</inArgs>";
cCoreScannerClass.ExecCommand(opcode, ref inXML, out outXML, out status);
while (true)
{
Console.Read();
}
}
private static void OnBarcodeEvent(short eventType, ref string pscanData)
{
Console.WriteLine("Scannner Event! Scan Data: " + pscanData);
}
}
}
Load pscanData in the XmlDocumentand your are ready to go, just copy this code:
private static void OnBarcodeEvent(short eventType, ref string pscanData)
{
Console.WriteLine("Scannner Event! Scan Data: " + pscanData);
XmlDocument xmlDoc = new XmlDocument();
//xmlDoc.LoadXml(pscanData); //You should use this line as far as your XML tags are correct
xmlDoc.LoadXml("<scandata>" +
"<modeldata>" +
"099909" +
"</modeldata>" +
"<datalabel>" +
"0x68 0x74 0x74" +
"</datalabel>" +
"</scandata>"); //I use this harcoded XML because I don't have your pscanData, just delete this line and uncoment the one above
XmlNodeList datalabel = xmlDoc.GetElementsByTagName("datalabel");
XmlNode allInDataLabel = datalabel.Item(0);
string whatDatalabelContains = allInDataLabel.InnerText;
Console.WriteLine("Datalabel: " + ToText(whatDatalabelContains));
}
Edit: Hex to text
private static string ToText(string yourHex)
{
StringBuilder sb = new StringBuilder();
string[] dataArr = yourHex.Split(new char[] { ' ' });
for (int i = 0; i < dataArr.Length; i++)
{
sb.Append(Char.ConvertFromUtf32(Convert.ToInt32(dataArr[i], 16)));
}
return sb.ToString();
}

Getting a System.StackOverflowException' error

I am Getting this error An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll I know you are not supposed to have an infinite loop but its not an infinate loop because it just has too go till it gets a file number that has not been made yet. How can i go about this a better way?
private int x = 0;
public string clients = #"F:\Internal Jobs\Therm-Air Files\Program\P-1-2.0\Clients\";
public string tdate = DateTime.Today.ToString("MM-dd-yy");
public void saveloop()
{
string path = LoadPO.Text.Substring(0, LoadPO.Text.LastIndexOf("\\"));
string name = Path.GetFileName(path);
string t = Convert.ToString(x);
if (!File.Exists(path + #"\" + name + ".xlsx")) // This Line throws error
{
oSheet.SaveAs(path + #"\" + name + "-" + t + ".xlsx");
string prop = /* snipped for space reasons, just string concats */
string Combine = string.Empty;
int b = 0;
int c = cf.cPanel.Controls.Count;
string[] items = new string[c];
foreach (WProduct ewp in cf.cPanel.Controls)
{
string item = /* snipped for space reasons, just string concats */
items[b] = item;
b += 1;
}
Combine = prop + "^<";
foreach (var strings in items)
{
Combine += strings + "<";
}
File.WriteAllText(path + #"\" + name + ".txt", Combine);
}
else
{
x += 1;
saveloop();
}
The reason the code above is failing is because you do not use i in the name of the file so you can increment all you want it does not change the name.
You need to abstract the creation of the name of the file from the code that does the writing. Think of it as writing code in blocks of functionality.
public static string GetFileName(string path, string name)
{
var fileName = $#"{path}\{name}.xlsx";
int i = 0;
while (System.IO.File.Exists(fileName))
{
i++;
fileName = $#"{path}\{name}({i}).xlsx";
}
return fileName;
}
public void saveloop()
{
var fileName = GetFileName(path, name);
// use fileName from this point on
}

How to close streamwriter correctly after if statement is no more true?

I am using streamwriter to save my data of the game while playing in a csv-file. In order to do this, I initialized my streamwriter in the startfunction and wrote a first line for the headers for my data. Then in the update function I write the changing game variables in that file. The problem I have is the following:
This works fine and I can see my csv file with the data when I click stop manually within the game. However, when I wait until myTimer (the duration of the game is <=0) and the GUI is reloading I just get an empty csv file.
I think the problem is related to the fact that I do not close my streamwriter correctly... Here is my code:
// Use this for initialization
public void Start ()
{
//create file (txt or csv) with streamwriter which has the name of the Subject and Information which game
swFeedbackGame = File.CreateText (UIManagerScript.SUBJECTID+"FeedbackGameData444.csv");
//write headers to file
swFeedbackGame.Write ("PositionRingFeeback" + "," + "PositionSphereMiddle" + "," + "distanceRingFeedbackTOSphere" + "," + "Collisions" + "," + "Timer"+System.Environment.NewLine);
}
public void SaveDataFeedback()
{
//start writing in file only when feedback game is starting
//if (StartButtonManager.startingGame) {
if (StartButtonManager.startingGame)
{
//get position of center of the ring
PositionRingFeedback = GameObject.Find ("Ring").transform.position;
//position of the center of the ring (y axis)
PositionRINGFeedback = PositionRingFeedback.y;
//error, meaning difference between position of the spheremiddle and center of the ring
distanceRingFeedbackTOSphere = PositionRINGFeedback - Sinewave.posSpheremiddle;
//write data to file _ columns are separated by a ,
swFeedbackGame.Write (PositionRINGFeedback + "," + Sinewave.posSpheremiddle + "," + distanceRingFeedbackTOSphere + "," + CounterManager.counterHitSinewave + "," + UIManagerScript.myTimer + System.Environment.NewLine);
swFeedbackGame.Flush ();
}
else
{
swFeedbackGame.Close ();
}
}
// Update is called once per frame
public void FixedUpdate ()
{
//saves the data from the FeedbackGame every Frame
SaveDataFeedback ();
}
Initialize your stream inside a using like so:
using(StreamWriter sw = new StreamWriter)
{
//your code here this
//this doesn't need a sw.Open(), or sw.Close()
}
but be careful if you have a nested streams.
You should avoid opening/closing files or keeping long gaps between open and close in different methods. Keep both the operations in same method.
The WriteAllText and AppendAllText static methods come in handy. They open the file, write the contents into it, and then close the file in just one statement.
Unless there will be too many calls to write contents to file, I would prefer using these methods, rather than explicitly opening and closing them myself.
// Use this for initialization
string FileName;
public void Start()
{
FileName = UIManagerScript.SUBJECTID + "FeedbackGameData444.csv";
//create file (txt or csv) with streamwriter which has the name of the Subject and Information which game
//and write headers to file
WriteToFile(FileName, true, "PositionRingFeeback" + "," + "PositionSphereMiddle" + "," + "distanceRingFeedbackTOSphere" + "," + "Collisions" + "," + "Timer" + System.Environment.NewLine);
}
public void SaveDataFeedback()
{
//start writing in file only when feedback game is starting
//if (StartButtonManager.startingGame) {
if (StartButtonManager.startingGame)
{
//get position of center of the ring
PositionRingFeedback = GameObject.Find("Ring").transform.position;
//position of the center of the ring (y axis)
PositionRINGFeedback = PositionRingFeedback.y;
//error, meaning difference between position of the spheremiddle and center of the ring
distanceRingFeedbackTOSphere = PositionRINGFeedback - Sinewave.posSpheremiddle;
//write data to file _ columns are separated by a ,
WriteToFile(FileName, false, PositionRINGFeedback + "," + Sinewave.posSpheremiddle + "," + distanceRingFeedbackTOSphere + "," + CounterManager.counterHitSinewave + "," + UIManagerScript.myTimer + System.Environment.NewLine);
}
}
// Update is called once per frame
public void FixedUpdate()
{
//saves the data from the FeedbackGame every Frame
SaveDataFeedback();
}
private void WriteToFile(string fileName, bool createNew, string contents)
{
if (createNew)
File.WriteAllText(fileName, contents);
else
File.AppendAllText(fileName, contents);
}
OOP comes to the resque.
Of course, it's verbouse a bit, but it's a good design which you always can extend and so on. Logic about logging is incapculated, so caller can dispose your logger itself and you just have to write whatever you want (note that you pass your game object data, and logger do everything for you). Sample code:
class Game
{
private readonly ILogger _logger;
public Game(ILogger logger)
{
_logger = logger;
}
public void Start()
{
_logger.StartWriting();
}
public void SaveDataFeedback()
{
var dataobject = new GameData();
// filling data object
_logger.WriteData(dataobject);
}
}
internal interface ILogger
{
void StartWriting();
void WriteData(GameData data);
}
public class GameData
{
public double PositionRingFeeback { get; set; }
public double PositionSphereMiddle { get; set; }
public double DistanceRingFeedbackToSphere { get; set; }
public int Collisions { get; set; }
public TimeSpan Timer { get; set; }
}
class FileLogger : ILogger, IDisposable
{
private readonly string _filename;
private StreamWriter _sr;
public FileLogger(string filename)
{
_filename = filename;
}
public void StartWriting()
{
_sr = new StreamWriter(new FileStream(_filename, FileMode.OpenOrCreate), Encoding.UTF8);
_sr.WriteLine("PositionRingFeeback" + "," + "PositionSphereMiddle" + "," + "distanceRingFeedbackTOSphere" + "," + "Collisions" + "," + "Timer");
}
public void WriteData(GameData data)
{
_sr.Write("{0}{1}{2}{3}{4}", data.PositionRingFeeback, data.PositionSphereMiddle, data.DistanceRingFeedbackToSphere, data.Collisions, data.Timer);
}
public void Dispose()
{
_sr.Dispose();
}
}
Then callee is disposing a logger itself:
using (var logger = new FileLogger("data.txt"))
{
var game = new Game(logger);
game.Start();
}
If you do not need such level of incapsulation, you can use just events:
class Game
{
public delegate void GameStartedHandler(Game sender, EventArgs eventArgs);
public delegate void GameEventHandler(Game sender, GameData eventData);
public event GameStartedHandler GameStarted = delegate { };
public event GameEventHandler GameEvent = delegate { };
public void Start()
{
GameStarted(this, EventArgs.Empty);
}
public void SaveDataFeedback()
{
var dataobject = new GameData();
// filling data object
GameEvent(this, dataobject);
}
}
but in this case callee is more complex because it should manage all logging itself:
using (var logger = new StreamWriter(new FileStream("data.txt", FileMode.OpenOrCreate), Encoding.UTF8))
{
var game = new Game();
game.GameStarted += (sender, eventArgs) => logger.WriteLine("PositionRingFeeback" + "," + "PositionSphereMiddle" + "," + "distanceRingFeedbackTOSphere" + "," + "Collisions" + "," + "Timer");
game.GameEvent += (sender, data) => logger.Write("{0}{1}{2}{3}{4}", data.PositionRingFeeback, data.PositionSphereMiddle, data.DistanceRingFeedbackToSphere, data.Collisions, data.Timer);
game.Start();
}

Serializing a manually written code

I am having a problem receiving files from the client. Someone suggested that I should use binary serialization to send and receive messages in stream. Can you give me ideas on how I should serialize this? I just learned about serialization not long ago so I am quite confused on how I should associate it with my program.
This is the client that 'should' be serialize
public void sendthedata()
{
if (!_timer.Enabled) // If timer is not running send data and start refresh interval
{
SendData();
_timer.Enabled = true;
}
else // Stop timer to prevent further refreshing
{
_timer.Enabled = false;
}
}
private List<int> listedProcesses = new List<int>();
private void SendData()
{
String processID = "";
String processName = "";
String processPath = "";
String processFileName = "";
String processMachinename = "";
listBox1.BeginUpdate();
try
{
piis = GetAllProcessInfos();
for (int i = 0; i < piis.Count; i++)
{
try
{
if (!listedProcesses.Contains(piis[i].Id)) //placed this on a list to avoid redundancy
{
listedProcesses.Add(piis[i].Id);
processID = piis[i].Id.ToString();
processName = piis[i].Name.ToString();
processPath = piis[i].Path.ToString();
processFileName = piis[i].FileName.ToString();
processMachinename = piis[i].Machinename.ToString();
output.Text += "\n\nSENT DATA : \n\t" + processFileName + "\n\t" + processMachinename + "\n\t" + processID + "\n\t" + processName + "\n\t" + processPath + "\n";
}
}
catch (Exception ex)
{
wait.Abort();
output.Text += "Error..... " + ex.StackTrace;
}
NetworkStream ns = tcpclnt.GetStream();
String data = "";
data = "--++" + processFileName + " " + processMachinename + " " + processID + " " + processPath;
if (ns.CanWrite)
{
byte[] bf = new ASCIIEncoding().GetBytes(data);
ns.Write(bf, 0, bf.Length);
ns.Flush();
}
}
}
finally
{
listBox1.EndUpdate();
}
}
And deserializing in the server
private void recieveData()
{
NetworkStream nStream = tcpClient.GetStream();
ASCIIEncoding ascii = null;
while (!stopRecieving)
{
if (nStream.CanRead)
{
byte[] buffer = new byte[1024];
nStream.Read(buffer, 0, buffer.Length);
ascii = new ASCIIEncoding();
recvDt = ascii.GetString(buffer);
/*Received message checks if it has +##+ then the ip is disconnected*/
bool f = false;
f = recvDt.Contains("+##+");
if (f)
{
string d = "+##+";
recvDt = recvDt.TrimStart(d.ToCharArray());
clientDis();
stopRecieving = true;
}
//else if (recvDt.Contains("^^"))
//{
// new Transmit_File().transfer_file(file, ipselected);
//}
/* ++-- shutsdown/restrt/logoff/abort*/
else if (recvDt.Contains("++--"))
{
string d = "++--";
recvDt = recvDt.TrimStart(d.ToCharArray());
this.Invoke(new rcvData(addToOutput));
clientDis();
}
/*--++ Normal msg*/
else if (recvDt.Contains("--++"))
{
string d = "--++";
recvDt = recvDt.TrimStart(d.ToCharArray());
this.Invoke(new rcvData(addToOutput));
}
}
Thread.Sleep(1000);
}
}
public void addToOutput()
{
if (recvDt != null && recvDt != "")
{
output.Text += "\n Received Data : " + recvDt;
recvDt = null;
}
}
Thank you.
There are a couple of rules to follow when serialising a piece of data.
It's easy to convert data to bytes, but consider how to reconstruct the data on the other side. Assume that the server can't have any knowledge on what you sended.
In your serialiser you just convert a couple of strings into a byte[] and send it over. Example:
string x = "abcdef";
string y = "ghijk";
var bytes = Encoding.Ascii.GetBytes(x + y);
the server receives: "abcdefghijk";
Is it possible for the server to determine and reconstruct strings x and y?
Since the server has no knowledge of the length of either x and y: no.
There are ways to solve this:
Use fixed length fields. In my example x should always be 6 chars and y should always be 5 chars in length. decoding on the server then becomes as trivial as
string x = data.Substring(0, 6)
string y = data.Substring(6, 5)
Use delimiters between the fields. If you are familiar with cvs, the ',' splits the fields. This however has it drawbacks, how to handle a ',' somewhere in a string? The data send over would be like "abcdef,ghijk"
Send the size of each field before the content of the field.
A naive approach just to clarify: string x would be send as '6abcdef' and y as '5ghijk'
Doing all this things by hand can get really hairy and is something that I would consider only if really needed.
I would resort to existing frameworks that do an excellent job on this subject:
Json.net
protobuf ported by Jon skeet
In this case I would first create a class to define the data send to the server instead of a bunch of strings:
class ProcessInfo{
public string ProcessID {get;set;}
public string ProcessName {get;set;}
public string ProcessPath {get;set;}
public string ProcessFileName {get;set;}
public string ProcessMachinename {get;set;}
};
the using Json to serialise this:
var procinfo = new ProcessInfo{
ProcessId = "1",
...
};
var serialised = JsonConvert.SerializeObject(procinfo);
var bytes = Encoding.Utf8.GetBytes(serialised);
ns.Write(bytes, 0, bytes.Length);
And restore it on the server just by:
var procInfo = JsonConvert.DeserializeObject<ProcessInfo>(json);

How to keep logs in C#?

This is a WinForm written in C#.
Lets say I'm generating a random named text file in my selected directory. When the button is clicked teh first time, i write the data contained in the textboxes into that text file. If the user wants to do the same thing with different data in the textboxes then the click on the button should write the new data into the text file without losing the old data. It's like keeping logs, is this possible?
My code is like:
private readonly Random setere = new Random();
private const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private string RandomString()
{
char[] buffer = new char[5];
for (int i = 0; i < 5; i++)
{
buffer[i] = chars[setere.Next(chars.Length)];
}
return new string(buffer);
}
private void button1_Click(object sender, EventArgs e)
{
DialogResult dia = MessageBox.Show("Wanna continue?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (dia == DialogResult.Yes)
{
StreamWriter wFile = new StreamWriter("C:\\Users\\Ece\\Documents\\Testings\\" + RandomString() + ".txt");
wFile.WriteLine("Name Surname:" + text1.Text + text2.Text);
wFile.WriteLine("Other:" + text3.Text + text4.Text);
wFile.WriteLine("Money:" + textBox1.Text + " TL.");
wFile.WriteLine("*************************************");
wFile.Close();
}
else
{
return;
}
}
You can append to the text in the file.
See
File.AppendText
using (StreamWriter sw = File.AppendText(pathofFile))
{
sw.WriteLine("This");
sw.WriteLine("is Extra");
sw.WriteLine("Text");
}
where pathofFile is the path to the file to append to.
Have a look at using something like this:
StreamWriter fw = new StreamWriter(#"C:\Logs\MyFile.txt",true);
fw.WriteLine("Some Message" + Environment.Newline);
fw.Flush();
fw.Close();
Hope that helps. See MSDN StreamWriter for more information
Updated: Removed old example
Also if you are trying to create a unique file you can use Path.GetRandomFileName()
Again from the MSDN Books:
The GetRandomFileName method returns a
cryptographically strong, random
string that can be used as either a
folder name or a file name.
UPDATED: Added a Logger class example below
Add a new class to your project and add the following lines (this is 3.0 type syntax so you may have to adjust if creating a 2.0 version)
using System;
using System.IO;
namespace LogProvider
{
//
// Example Logger Class
//
public class Logging
{
public static string LogDir { get; set; }
public static string LogFile { get; set; }
private static readonly Random setere = new Random();
private const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public Logging() {
LogDir = null;
LogFile = null;
}
public static string RandomFileName()
{
char[] buffer = new char[5];
for (int i = 0; i < 5; i++)
{
buffer[i] = chars[setere.Next(chars.Length)];
}
return new string(buffer);
}
public static void AddLog(String msg)
{
String tstamp = Convert.ToString(DateTime.Now.Day) + "/" +
Convert.ToString(DateTime.Now.Month) + "/" +
Convert.ToString(DateTime.Now.Year) + " " +
Convert.ToString(DateTime.Now.Hour) + ":" +
Convert.ToString(DateTime.Now.Minute) + ":" +
Convert.ToString(DateTime.Now.Second);
if(LogDir == null || LogFile == null)
{
throw new ArgumentException("Null arguments supplied");
}
String logFile = LogDir + "\\" + LogFile;
String rmsg = tstamp + "," + msg;
StreamWriter sw = new StreamWriter(logFile, true);
sw.WriteLine(rmsg);
sw.Flush();
sw.Close();
}
}
}
Add this to your forms onload event
LogProvider.Logging.LogDir = "C:\\Users\\Ece\\Documents\\Testings";
LogProvider.Logging.LogFile = LogProvider.Logging.RandomFileName();
Now adjust your button click event to be like the following:
DialogResult dia = MessageBox.Show("Wanna continue?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (dia == DialogResult.Yes)
{
StringBuilder logMsg = new StringBuilder();
logMsg.Append("Name Surname:" + text1.Text + text2.Text + Environment.NewLine);
logMsg.Append("Other:" + text3.Text + text4.Text + Environment.NewLine);
logMsg.Append("Money:" + textBox1.Text + " TL." + Environment.NewLine);
logMsg.Append("*************************************" + Environment.NewLine);
LogProvider.Logging.AddLog(logMsg.ToString());
} else
{
return;
}
Now you should only create one file for the entire time that application is running and will log to that one file every time you click your button.
You might want to take a look at log4net and the RollingFileAppender
Sure. Just open the file for appending with something like System.IO.File.AppendText

Categories