Vlc.DotNet.Core taking snapshot while streaming - c#

I am using Vlc.DotNet.Core for multicast video streaming. Also, I want to take snapshots. For testing, I am working on a simple program that calling snapshot function for every 2 seconds. However snapshot function is not working, when TakeSnapshot function called, it is not calling OnMediaPlayerSnapshotTaken event.
Besides that, I made a snapshot tests for Vlc.DotNet.Forms library and its working quite well.
The simple code I am working on is given below :
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using Vlc.DotNet.Core;
namespace SnapshotTest
{
class Program
{
static void Main(string[] args)
{
VlcStreamerSnapshotText myObject = new VlcStreamerSnapshotText();
myObject.streamFile();
}
}
class VlcStreamerSnapshotText
{
System.Timers.Timer aTimer = new System.Timers.Timer();
static Vlc.DotNet.Core.VlcMediaPlayer mediaPlayer;
public bool streamFile(string source = "")
{
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 2000;
aTimer.Enabled = true;
var currentDirectory = Directory.GetCurrentDirectory();
var libDirectory = new DirectoryInfo(Path.Combine(currentDirectory, "libvlc", IntPtr.Size == 4 ? "x86" : "x64"));
var options = new string[]
{
"--no-snapshot-preview",
"--no-audio"
//"--no-video"
// VLC options can be given here. Please refer to the VLC command line documentation.
};
mediaPlayer = new Vlc.DotNet.Core.VlcMediaPlayer(new DirectoryInfo(libDirectory.FullName), options);
string[] mediaOptions = new string[]
{
":sout=#duplicate{dst=rtp{sdp=rtsp://127.0.0.1:1000/},dst=display}",
":sout-all",
":sout-keep"
};
//string[] mediaOptions = new string[] { string.Concat("--sout=#duplicate{dst=rtp{sdp=rtsp://", IpAddress, ":", "1000", "/}} --sout-all --sout-keep") };
mediaPlayer.SetMedia(new Uri("http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_h264.mov"), mediaOptions);
mediaPlayer.SnapshotTaken += OnMediaPlayerSnapshotTaken;
bool playFinished = false;
mediaPlayer.PositionChanged += (sender, e) =>
{
Console.Write("\r" + Math.Floor(e.NewPosition * 100) + "%");
};
mediaPlayer.EncounteredError += (sender, e) =>
{
Console.Error.Write("An error occurred");
playFinished = true;
};
mediaPlayer.EndReached += (sender, e) =>
{
playFinished = true;
};
Task.Factory.StartNew(() => mediaPlayer.Play());
//mediaPlayer.Play();
// Ugly, sorry
while (!playFinished)
{
Thread.Sleep(TimeSpan.FromMilliseconds(500));
}
return true;
}
ManualResetEvent m_mreSnapshot = new ManualResetEvent(false);
private readonly object m_snapLock = new object();
private bool m_SnapshotIsTaken = false;
public bool GetSnapshot()
{
m_SnapshotIsTaken = false;
if (mediaPlayer == null)
{
return false;
}
string currentTime = DateTime.Now.ToString("yyyyMMdd_HHmmss");
string uniqueId = generateID(string.Empty);
string snapName = string.Format("{0}_{1}.png", currentTime, uniqueId);
string tempFilePathCand = Path.GetTempPath();
if (!tempFilePathCand.EndsWith("\\"))
tempFilePathCand = tempFilePathCand + "\\" + snapName;
else
tempFilePathCand = tempFilePathCand + snapName;
FileInfo snapPathInfo = new FileInfo(tempFilePathCand);
//mediaPlayer.Manager.TakeSnapshot();
mediaPlayer.TakeSnapshot(snapPathInfo);
m_mreSnapshot.WaitOne(TimeSpan.FromSeconds(2));
if (m_SnapshotIsTaken)
return true;
return false;
}
private string generateID(string tip)
{
return string.Format(#"{0}_{1}", tip, Guid.NewGuid().ToString("N"));
}
void OnMediaPlayerSnapshotTaken(object sender, VlcMediaPlayerSnapshotTakenEventArgs e)
{
mediaPlayer.SnapshotTaken -= OnMediaPlayerSnapshotTaken;
m_SnapshotIsTaken = true;
mediaPlayer.SnapshotTaken += OnMediaPlayerSnapshotTaken;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
GetSnapshot();
}
}
}
So, What am I missing?

Maybe a bug in Vlc.DotNet: https://github.com/ZeBobo5/Vlc.DotNet/issues/447
Are you using Vlc.DotNet v3?

Related

Timer Working for two times only , c# console application

I have C# Console Application It's working just two times only .
when i use singleton pattern to call my class and method , i don't know where is the problem exactly in my code and also i use two One xml file to write and read data from it ,when i use external url service to read data , when i have only two c# classes :
Programe.cs , Tanks_Controller.cs
this my code i used it :
using System;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Net;
using System.Reflection;
using System.Text;
using System.Timers;
using System.Xml;
using log4net;
using NHibernate;
using Configuration = NHibernate.Cfg.Configuration;
namespace Tank_Gauging.Franklin
{
public class TankController
{
private static readonly ILog Log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static Timer aTimer;
private static int tankCode;
private static string WaterHeight { get; set; }
private static string WaterVolume { get; set; }
private static double ProductHeight { get; set; }
private static double ProductVolume { get; set; }
private static double Temperature { get; set; }
private static double ProductTcVolume { get; set; }
private static double ProductUllage { get; set; }
static Timer _timer; // From System.Timers
private NameValueCollection customConfig =
ConfigurationManager.GetSection("CustomConfiguration") as NameValueCollection;
private static string _urlService = null;
private Timer timer1;
private static TankController instance;
static int alarmCounter = 1;
static bool exitFlag = false;
private TankController()
{
// init();
}
public static TankController Instance
{
get
{
if (instance == null)
{
instance = new TankController();
}
<p> return</p>instance;
}
}
public void init()
{
_urlService = customConfig["DemoUrlService"];
// onStart();
Timer aTimer = new Timer();
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = Convert.ToDouble(getIntervialTimeIntervalTime());
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
// Specify what you want to happen when the Elapsed event is raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
getTankStatus();
Log.Warn($#"Timer is set to : {e.SignalTime}");
}
private static bool getTankStatus()
{
ServicePointManager.Expect100Continue = false;
string responseStr = null;
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(_urlService);
byte[] bytes;
bytes = Encoding.ASCII.GetBytes(
"<TSA_REQUEST_LIST PASSWORD=''><TSA_REQUEST COMMAND=''/></TSA_REQUEST_LIST>"); // header request .
request.ContentType = "text/xml; encoding=utf-8";
request.ContentLength = bytes.Length;
request.Method = "POST";
Stream requestStream = request.GetRequestStream();
requestStream.Write(bytes, 0, bytes.Length);
requestStream.Close();
HttpWebResponse response;
response = (HttpWebResponse) request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
Stream responseStream = response.GetResponseStream();
responseStr = new StreamReader(responseStream).ReadToEnd();
}
File.WriteAllText(#"C:\user\tanks_data.xml", string.Empty); // Remove everything in file .
File.WriteAllText(#"C:\user\tanks_data.xml", responseStr); // add new data response from service .
XmlTextReader reader = new XmlTextReader(#"C:\user\tanks_data.xml"); // write data from xml file .
var counter = 1;
var sessionFactory = new Configuration().BuildSessionFactory();
var mySession = sessionFactory.OpenSession();
var n = 1;
while (reader.Read())
{
if (reader.Name == "TANK_STATUS")
{
Console.WriteLine($"------------------------------ {counter} ----------------------------------");
while (reader.MoveToNextAttribute())
{
/*reader.Name == "TANK_ID" */
if (reader.Name == "TANK_ID")
{
tankCode = Int32.Parse(reader.Value);
Log.Debug("TANK_ID = " + tankCode);
}
if (reader.Name == "WATER_LEVEL")
{
WaterHeight = reader.Value;
Convert.ToDouble(reader.Value);
Log.Debug("WATER_LEVEL = " + WaterHeight);
}
if (reader.Name == "WATER_VOLUME")
{
WaterVolume = reader.Value; //Convert.ToDouble();
Log.Debug("WATER_VOLUME = " + WaterVolume);
}
if (reader.Name == "PRODUCT_LEVEL")
{
ProductHeight = Convert.ToDouble(reader.Value);
Log.Debug("WATER_VOLUME = " + WaterVolume);
}
if (reader.Name == "TEMPERATURE")
{
Temperature = Convert.ToDouble(reader.Value);
Log.Debug("TEMPERATURE = " + Temperature);
}
if (reader.Name == "ULLAGE_VOLUME")
{
ProductUllage = Convert.ToDouble(reader.Value);
Log.Debug("ULLAGE_VOLUME = " + ProductUllage);
}
if (reader.Name == "GROSS_PRODUCT_VOLUME")
{
ProductTcVolume = Convert.ToDouble(reader.Value);
Log.Debug("GROSS_PRODUCT_VOLUME = " + ProductTcVolume);
}
if (reader.Name == "NET_PRODUCT_VOLUME")
{
ProductVolume = Convert.ToDouble(reader.Value);
Log.Debug("NET_PRODUCT_VOLUME = " + ProductVolume);
}
}
counter++;
n++;
try
{
mySession.BeginTransaction();
mySession.CreateSQLQuery(
#" INSERT INTO GA_TANK_TRANSACTIONS (
BRANCH_ID,
WATER_VOLUME,
ULLAGE_VOLUME,
LIQUID_VOLUME,
YEAR_CODE,
SEQ,
TRANS_DATE,
TANK_CODE,
WATER_HEIGHT,
LIQUID_TEMPERATURE,
TYPE_CODE,
USER_ID,
LIQUID_HEIGHT,
LIQUID_MASS,
LIQUID_DENSITY,
LIQUID_TC_VOLUME,
TRANS_HOUR,
TRANS_MINUTE)
VALUES (:branchId,
(:waterVolume ),
:ullageVolume,
(:liquidVolume ),
:yearCode,
(SELECT NVL(MAX(SEQ), 0) + 1
FROM GA_TANK_TRANSACTIONS
WHERE BRANCH_ID = :branchId
AND YEAR_CODE = :yearCode
AND TYPE_CODE = 1066),
TRUNC(SYSDATE),
:tankCode,
(:waterHeight*1000),
:liquidTemperature,
1066,
NULL,
(:liquidHeight *1000),
:liquidMass,
:liquidDensity,
:liquidTCVolume,
TO_NUMBER(TO_CHAR(SYSDATE, 'hh24')),
TO_NUMBER(TO_CHAR(SYSDATE, 'mi')))")
.SetParameter("branchId", "1")
.SetParameter("tankCode", tankCode + "")
.SetParameter("yearCode", DateTime.Today.Year)
.SetParameter("waterHeight", WaterHeight)
.SetParameter("liquidMass", getLiquidMass(tankCode, ProductVolume))
.SetParameter("liquidHeight", ProductHeight)
.SetParameter("liquidTemperature", Temperature)
.SetParameter("liquidDensity", 0)
.SetParameter("liquidTCVolume", Temperature)
.SetParameter("waterVolume", WaterVolume)
.SetParameter("ullageVolume", ProductUllage)
.SetParameter("liquidVolume", ProductVolume)
.ExecuteUpdate();
mySession.Transaction.Commit();
mySession.Clear();
}
catch (Exception e)
{
Log.Debug(e);
throw;
}
}
}
Log.Debug("Successfully Commit Script .");
return true;
}
private string getIntervialTimeIntervalTime()
{
try
{
var sessionFactory = new Configuration().BuildSessionFactory();
var mySession = sessionFactory.OpenSession();
var probeTimeInterval =
mySession.CreateSQLQuery(
"SELECT NVL(GE_PKG.GET_GE_VALUE(1, 47, 313), 1) AS \"probeTimeInterval\" FROM dual")
.AddScalar("probeTimeInterval", NHibernateUtil.Int64)
.UniqueResult<long?>() * 100;
Log.Debug($"Success Get Prop Interval Time {probeTimeInterval} sec ");
return probeTimeInterval + "";
}
catch (Exception e)
{
Log.Debug(e);
throw;
}
<p> return</p>null;
}
private static double getLiquidMass(int tankCode, double liquidVolume)
{
try
{
var sessionFactory = new Configuration().BuildSessionFactory();
var mySession = sessionFactory.OpenSession();
var liquidMass =
mySession.CreateSQLQuery(
$#"SELECT NVL(FUEL_TYPE_DENSITY, 0)* NVL(:liquidVolume, 0) AS liquidMass
FROM GA_FUEL_TYPE
WHERE EXISTS(
SELECT 1
FROM GA_FUEL_TANKS
WHERE GA_FUEL_TANKS.FUEL_CODE = GA_FUEL_TYPE.TYPE_CODE
AND TANK_CODE = :tankCode
AND BRANCH_ID = :branchId)"
)
.AddScalar("liquidMass", NHibernateUtil.Double)
.SetParameter("tankCode", tankCode)
.SetParameter("branchId", "1")
.SetParameter("liquidVolume", liquidVolume)
.UniqueResult<double>();
Log.Debug($"Success Get Liquid Mass {liquidMass} ");
<p> return</p> liquidMass;
}
catch (Exception e)
{
Log.Debug(e);
throw;
}
<p> return</p> 0;
}
}
}
My Timer Code :
_urlService = customConfig["DemoUrlService"];
// onStart();
Timer aTimer = new Timer();
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = Convert.ToDouble(getIntervialTimeIntervalTime());
aTimer.AutoReset = true;
aTimer.Enabled = true;
You are cresting a LOCAL variable of your Timer, you should instead use your GLOBAL instance, like this:
public void init()
{
_urlService = customConfig["DemoUrlService"];
// onStart();
aTimer = new Timer();
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = Convert.ToDouble(getIntervialTimeIntervalTime());
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
The problem, when you use a local Timer, is that when the method exits, the Timer get garbage collected and of course stops working.

How to implement a Timeout on WebClient.DownloadFileAsync

So I thought Webclient.DownloadFileAysnc would have a default timeout but looking around the documentation I cannot find anything about it anywhere so I'm guessing it doesn't.
I am trying to download a file from the internet like so:
using (WebClient wc = new WebClient())
{
wc.DownloadProgressChanged += ((sender, args) =>
{
IndividualProgress = args.ProgressPercentage;
});
wc.DownloadFileCompleted += ((sender, args) =>
{
if (args.Error == null)
{
if (!args.Cancelled)
{
File.Move(filePath, Path.ChangeExtension(filePath, ".jpg"));
}
mr.Set();
}
else
{
ex = args.Error;
mr.Set();
}
});
wc.DownloadFileAsync(new Uri("MyInternetFile", filePath);
mr.WaitOne();
if (ex != null)
{
throw ex;
}
}
But if I turn off my WiFi (simulating a drop of internet connection) my application just pauses and the download stops but it will never report that through to the DownloadFileCompleted method.
For this reason I would like to implement a timeout on my WebClient.DownloadFileAsync method. Is this possible?
As an aside I am using .Net 4 and don't want to add references to third party libraries so cannot use the Async/Await keywords
You can use WebClient.DownloadFileAsync(). Now inside a timer you can call CancelAsync() like so:
System.Timers.Timer aTimer = new System.Timers.Timer();
System.Timers.ElapsedEventHandler handler = null;
handler = ((sender, args)
=>
{
aTimer.Elapsed -= handler;
wc.CancelAsync();
});
aTimer.Elapsed += handler;
aTimer.Interval = 100000;
aTimer.Enabled = true;
Else create your own weclient
public class NewWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
var req = base.GetWebRequest(address);
req.Timeout = 18000;
return req;
}
}
Create a WebClientAsync class that implements the timer in the constructor. This way you aren't copying and pasting the timer code into every implementation.
public class WebClientAsync : WebClient
{
private int _timeoutMilliseconds;
public EdmapWebClientAsync(int timeoutSeconds)
{
_timeoutMilliseconds = timeoutSeconds * 1000;
Timer timer = new Timer(_timeoutMilliseconds);
ElapsedEventHandler handler = null;
handler = ((sender, args) =>
{
timer.Elapsed -= handler;
this.CancelAsync();
});
timer.Elapsed += handler;
timer.Enabled = true;
}
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
request.Timeout = _timeoutMilliseconds;
((HttpWebRequest)request).ReadWriteTimeout = _timeoutMilliseconds;
return request;
}
protected override voidOnDownloadProgressChanged(DownloadProgressChangedEventArgs e)
{
base.OnDownloadProgressChanged(e);
timer.Reset(); //If this does not work try below
timer.Start();
}
}
This will allow you to timeout if you lose Internet connection while downloading a file.
Here is another implementation, I tried to avoid any shared class/object variables to avoid trouble with multiple calls:
public Task<string> DownloadFile(Uri url)
{
var tcs = new TaskCompletionSource<string>();
Task.Run(async () =>
{
bool hasProgresChanged = false;
var timer = new Timer(new TimeSpan(0, 0, 20).TotalMilliseconds);
var client = new WebClient();
void downloadHandler(object s, DownloadProgressChangedEventArgs e) => hasProgresChanged = true;
void timerHandler(object s, ElapsedEventArgs e)
{
timer.Stop();
if (hasProgresChanged)
{
timer.Start();
hasProgresChanged = false;
}
else
{
CleanResources();
tcs.TrySetException(new TimeoutException("Download timedout"));
}
}
void CleanResources()
{
client.DownloadProgressChanged -= downloadHandler;
client.Dispose();
timer.Elapsed -= timerHandler;
timer.Dispose();
}
string filePath = Path.Combine(Path.GetTempPath(), Path.GetFileName(url.ToString()));
try
{
client.DownloadProgressChanged += downloadHandler;
timer.Elapsed += timerHandler;
timer.Start();
await client.DownloadFileTaskAsync(url, filePath);
}
catch (Exception e)
{
tcs.TrySetException(e);
}
finally
{
CleanResources();
}
return tcs.TrySetResult(filePath);
});
return tcs.Task;
}

How to get OnPresence and OnRosterList to not be non-responsive

Currently, I am able to be connected to the server, and I was able to set my "status" and my presence. However, I am unable to get my "friends/buddies/contacts" to come up.
xmpp = new XmppClientConnection();
xmpp.ConnectServer =
xmpp.UseSSL = true;
xmpp.Port = 5223;
xmpp.Server =
xmpp.Resource =
xmpp.UseSSL = true;
xmpp.Port = 5223;
xmpp.Username = username;
xmpp.Password = password;
xmpp.SocketConnectionType = SocketConnectionType.Direct;
xmpp.AutoRoster = true;
xmpp.AutoPresence = true;
xmpp.AutoResolveConnectServer = false;
xmpp.AutoAgents = false;
xmpp.RegisterAccount = false;
xmpp.UseCompression = false;
xmpp.OnReadXml += new XmlHandler(OnReadXml);
xmpp.OnWriteXml += new XmlHandler(OnWriteXml);
xmpp.OnStreamError += new XmppElementHandler(OnStreamError);
xmpp.OnSocketError += new ErrorHandler(OnSocketError);
xmpp.ClientSocket.OnValidateCertificate += new RemoteCertificateValidationCallback(ClientSocket_OnValidateCertificate);
xmpp.OnIq += new IqHandler(OnIq);
xmpp.OnRosterStart += new ObjectHandler(OnRosterStart);
xmpp.OnRosterItem += new agsXMPP.XmppClientConnection.RosterHandler(OnRosterItem);
xmpp.OnRosterEnd += new ObjectHandler(OnRosterEnd);
xmpp.OnPresence += new PresenceHandler(OnPresence);
xmpp.OnMessage += new MessageHandler(OnMessage);
xmpp.OnError += new ErrorHandler(OnError);
xmpp.OnLogin += new ObjectHandler(OnLogin);
xmpp.OnAuthError += new XmppElementHandler(OnAuthError);
xmpp.OnClose += new ObjectHandler(OnClose);
xmpp.OnSaslStart += new agsXMPP.sasl.SaslEventHandler(OnSaslStart);
try { xmpp.Open(); }
catch { }
do { Thread.Sleep(300); }
while (!xmpp.Authenticated);
for (bool IsBinding = false; IsBinding == false; Thread.Sleep(1000))
if (xmpp.XmppConnectionState.ToString().CompareTo("Binding") != 0)
IsBinding = true;
And for my OnPresence and OnRosterList I have (unfortunately, none of the following works.):
private void OnRosterStart(object sender)
{
Console.WriteLine("Roster has started.");
}
private void OnRosterItem(object sender, agsXMPP.protocol.iq.roster.RosterItem item)
{
messenger.AddToRoster(item.Name);
messenger.AddToRoster(item.Jid.User);
}
private void OnRosterEnd(object sender)
{
Console.WriteLine("Roster has ended.");
}
private void OnPresence(object sender, Presence pres)
{
MessageBox.Show("Hello");
Console.WriteLine("Here are your contacts: ");
Console.WriteLine("{0}#{1} {2}", pres.From.User, pres.From.Server, pres.Type);
}
http://puu.sh/gr73T/a8595b59aa.png
Thanks.
Problem Statement: Initially, OnPresence doesn't do anything. (I understand it is an async function, however, it is clearly not working after keeping the application open for 30 minutes waiting.) Furthermore, I'd thought I heard somewhere that OnPresence should be handled once you send your presence to the server, however I am not getting my "contacts/friends/ buddies" presence at all.
Solution:
I have gotten this resolved. The solution is to not run any of these handlers in a thread. ;)

Can anyone see a problem with the way I'm redirecting the output of these processes?

Alright so I'm having a problem with threading. I'm instantiating a new "ExecuteThread" class, and firing off a new thread to run the method "ThreadProccess" in that new reference, multiple times asynchronously. Now all the process start and run and finish asynchronously PERFECTLY. The problem is, I need to redirect those processes' output. As soon as I uncomment the line that is commented down there, everything goes out of wack and starts running consecutively, and returning the wrong elapsed times and such. (The elapsed times were correct before). And I need this line because it is where it stores the output. Can anyone see a problem with the way I'm redirecting these outputs?
public class ExecuteThread
{
private string exePath;
private string gPath;
private string filePath;
private string tPath;
private Dictionary<string, string> gReference;
private Entry entry;
private startNextThread callBackDelegate;
private ProcessStartInfo startInfo;
private PInfo pInfo;
private Process filePExe;
public ExecuteThread(Entry entry, string exe, Dictionary<string, string> gReference, startNextThread callBack)
{
pInfo = new PInfo();
this.entry = entry;
this.gReference = gReference;
exePath = exe;
callBackDelegate = callBack;
getPInfo();
createStartInfo();
InstantiateProcess();
}
private void getPInfo()
{
GetGPath();
filePath = entry.ResolveSourcePath(entry);
tPath = entry.ResolveArtifactsTagsPath(entry);
}
private void GetGPath()
{
if (!string.IsNullOrEmpty(entry.fileType))
{
if (g.ContainsKey(entry.fileType))
gPath = gReference[entry.fileType];
return;
}
gPath = null;
}
private void createStartInfo()
{
startInfo = new ProcessStartInfo(exePath);
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = gPath + " " + filePath + " " + tPath;
}
private void InstantiateProcess()
{
filePExe = new Process();
filePExe.StartInfo = startInfo;
filePExe.EnableRaisingEvents = true;
}
private void Parse()
{
try
{
this.filePExe.Start();
this.fileParserExe.WaitForExit();
//this.pInfo.additionalMessage += filePExe.StandardOutput.ReadToEnd();
this.filePExe.Close();
}
catch (Exception e)
{
parseInfo.additionalMessage += e.ToString();
parseInfo.additionalMessage += "Could not locate single file p executable: " + exePath;
}
}
public void ThreadProcess()
{
this.pInfo.fileName = entry.fileName;
this.pInfo.startTime = DateTime.Now;
Parse();
this.pInfo.endTime = DateTime.Now;
this.pInfo.SetElapsedTime();
if (this.callBackDelegate != null)
{
this.callBackDelegate(this.pInfo);
}
}
}
public class PInfo
{
public string fileName;
public DateTime startTime;
public DateTime endTime;
public string ElapsedTime;
public string additionalMessage = "";
public void SetElapsedTime()
{
TimeSpan elapsedTime;
elapsedTime = this.endTime.Subtract(this.startTime);
ElapsedTime = string.Format("{0:hh\\:mm\\:ss.fff}", elapsedTime);
}
}
//How I'm starting each thread
if (entryQueue.Count > 0)
{
ExecuteThread eT = new ExecuteThread(entryQueue.Dequeue(), exe, gReference,
new startNextThread(startNextThread));
Thread newThread = new Thread(eT.ThreadProcess);
newThread.Start();
}
You should put the line you commented before the call to WaitForExit. For more info, see the Remarks section of the documentation.
Additionally, you should use the Stopwatch class to measure the duration of an operation. See the Remarks section of DateTime.Now for more info.
UPDATE:
You could try using the async reading of the output stream to see whether this helps. For this, change your Parse method like this:
this.filePExe.OutputDataReceived +=
(s, e) => this.pInfo.additionalMessage += e.Data + Environment.NewLine;
this.filePExe.Start();
this.filePExe.BeginOutputReadLine();
this.filePExe.WaitForExit();
this.filePExe.Close();

C# Auto Update Program

OK, I am working on a program that will automatically download an update if the versions don't match.
The problem now is that it loads the info from an XML file, but it doesn't download the files specified.
Any suggestions to improve the code are welcome as well!
Here is the complete source code:
http://www.mediafire.com/?44d9mcuhde9fv3e
http://www.virustotal.com/file-scan/report.html?id=178ab584fd87fd84b6fd77f872d9fd08795f5e3957aa8fe7eee03e1fa9440e74-1309401561
Thanks in advance for the help!
EDIT
The File to download, specified in Program.cs does not download and the program gets stuck at
currentFile = string.Empty;
label1.Text = "Preparing to download file(s)...";
Thread t = new Thread(new ThreadStart(DownloadFiles)); // Making a new thread because I prefer downloading 1 file at a time
t.Start();
and it start the "Thread t".
Code that seems to be making problems:
UpdateForm.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.NetworkInformation;
using System.Net;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Xml;
using System.Xml.Linq;
using System.Runtime.InteropServices;
namespace LauncherBeta1
{
public partial class UpdateForm : Form
{
const int MF_BYPOSITION = 0x400;
[DllImport("User32")]
private static extern int RemoveMenu(IntPtr hMenu, int nPosition, int wFlags);
[DllImport("User32")]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("User32")]
private static extern int GetMenuItemCount(IntPtr hWnd);
private static WebClient webClient = new WebClient();
internal static List<Uri> uriFiles = new List<Uri>();
internal static Uri uriChangelog = null;
private static long fileSize = 0, fileBytesDownloaded = 0;
private static Stopwatch fileDownloadElapsed = new Stopwatch();
bool updateComplete = false, fileComplete = false;
string currentFile = string.Empty, labelText = string.Empty;
int progbarValue = 0, KBps = 0;
public UpdateForm()
{
IntPtr hMenu = GetSystemMenu(this.Handle, false);
int menuItemCount = GetMenuItemCount(hMenu);
RemoveMenu(hMenu, menuItemCount - 1, MF_BYPOSITION);
InitializeComponent();
XmlDocument xdoc = new XmlDocument();
xdoc.Load("http://raiderz.daregamer.com/updates/app_version.xml");
XmlNode xNodeVer = xdoc.DocumentElement.SelectSingleNode("Version");
FileVersionInfo fileVer = FileVersionInfo.GetVersionInfo(AppDomain.CurrentDomain.BaseDirectory + "lua5.1.dll");
int ver_app = Convert.ToInt32(fileVer.FileVersion.ToString());
int ver_xml = Convert.ToInt32(xNodeVer);
if (ver_xml == ver_app)
{
Application.Run(new Form1());
Environment.Exit(0);
}
else
{
if (ver_xml < ver_app || ver_xml > ver_app)
{
if (uriChangelog != null)
{
label1.Text = "Status: Downloading changelog...";
try
{
string log = webClient.DownloadString(uriChangelog);
log = log.Replace("\n", Environment.NewLine);
txtboxChangelog.Text = log;
}
catch (WebException ex) { }
}
foreach (Uri uri in uriFiles)
{
string uriPath = uri.OriginalString;
currentFile = uriPath.Substring(uriPath.LastIndexOf('/') + 1);
if (File.Exists(currentFile))
{
label1.Text = "Status: Deleting " + currentFile;
File.Delete(currentFile);
}
}
currentFile = string.Empty;
label1.Text = "Preparing to download file(s)...";
Thread t = new Thread(new ThreadStart(DownloadFiles)); // Making a new thread because I prefer downloading 1 file at a time
t.Start();
}
else
{
//MessageBox.Show("Client is up to date!");
Application.Run(new Form1());
Environment.Exit(0);
}
}
}
private void DownloadFiles()
{
foreach (Uri uri in uriFiles)
{
try
{
fileComplete = false;
fileDownloadElapsed.Reset();
fileDownloadElapsed.Start();
string uriPath = uri.OriginalString;
currentFile = uriPath.Substring(uriPath.LastIndexOf('/') + 1);
webClient.DownloadFileAsync(uri, currentFile);
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadFileCompleted);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressChanged);
while (!fileComplete) { Thread.Sleep(1000); }
}
catch { continue; }
}
currentFile = string.Empty;
updateComplete = true;
}
void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progbarValue = e.ProgressPercentage;
fileSize = e.TotalBytesToReceive / 1024;
fileBytesDownloaded = e.BytesReceived / 1024;
if (fileBytesDownloaded > 0 && fileDownloadElapsed.ElapsedMilliseconds > 1000)
{
KBps = (int)(fileBytesDownloaded / (fileDownloadElapsed.ElapsedMilliseconds / 1000));
}
labelText = "Status: Downloading " + currentFile +
"\n" + fileBytesDownloaded + " KB / " + fileSize + " KB - " + KBps + " KB/s";
}
void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
progbarValue = 0;
fileComplete = true;
}
/// <summary>
/// Returns file size (Kb) of a Uri
/// </summary>
/// <param name="uri"></param>
/// <returns></returns>
private long GetFileSize(Uri uri)
{
try
{
WebRequest webRequest = HttpWebRequest.Create(uri);
using (WebResponse response = webRequest.GetResponse())
{
long size = response.ContentLength;
return size / 1024;
}
}
catch { return 1; }
}
private void timerMultiPurpose_Tick(object sender, EventArgs e)
{
if (updateComplete == true)
{
updateComplete = false;
label1.Text = "Status: Complete";
progressBar1.Value = 0;
MessageBox.Show("Update complete!!");
Application.Run(new Form1());
Environment.Exit(0);
}
else
{
progressBar1.Value = progbarValue;
label1.Text = labelText;
}
}
private void UI_FormClosing(object sender, FormClosingEventArgs e)
{
Environment.Exit(0);
}
}
}
Relevant code from Program.cs:
System.Threading.Thread.Sleep(1000); // Give the calling application time to exit
XmlDocument xdoc = new XmlDocument();
xdoc.Load("http://raiderz.daregamer.com/updates/app_version.xml");
XmlNode xNodeVer = xdoc.DocumentElement.SelectSingleNode("Loc");
string ver_xml = Convert.ToString(xNodeVer);
args = new string[2];
args[0] = "Changelog=http://raiderz.daregamer.com/updates/changelog.txt";
args[1] = "URIs=" + ver_xml;
if (args.Length == 0)
{
MessageBox.Show("Can not run program without parameters", "Error");
return;
}
try
{
foreach (string arg in args)
{
if (arg.StartsWith("URIs="))
{
string[] uris = arg.Substring(arg.IndexOf('=') + 1).Split(';');
foreach (string uri in uris)
{
if (uri.Length > 0)
{
UpdateForm.uriFiles.Add(new Uri(uri));
}
}
}
else if (arg.StartsWith("Changelog="))
{
UpdateForm.uriChangelog = new Uri(arg.Substring(arg.IndexOf('=') + 1));
}
}
}
catch { MessageBox.Show("Missing or faulty parameter(s)", "Error"); }
I've not downloaded or reviewed your code, but if this is all C# based and on the v2.0 framework or higher you may want to check in to using ClickOnce. It will handle much of the auto updating for you and even allow users to continue using the program if they are offline and unable to connect to your update server.

Categories