Unable to start Windows Service if reference is used - c#

I have create a windows service. when i try to start the service, i recieve the error
Windows could not start the Auto Process service on Local Computer.
Error 1053: The service did not respond to the start or control request in a timely fashion.
This is my code
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Timers;
using Drone.Engine; //
namespace Auto
{
public partial class Service1 : ServiceBase
{
static string month = DateTime.Now.ToString("MMM");
private Timer timer = new Timer();
private Dictionary<string, bool> processStatus = new Dictionary<string, bool>();
private Executor worker = new Executor(); //
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
processStatus.Add("start", false);
processStatus.Add("stop", false);
System.Threading.Thread.Sleep(10000);
WriteToFile("Service Started at " + DateTime.Now);
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 2000;
timer.Enabled = true;
}
private void OnElapsedTime(object sender, ElapsedEventArgs e)
{
foreach (var process in processStatus.Where(v => v.Value == false))
{
WriteToFile(process.Key + " Sync Started at " + DateTime.Now);
ChangeProcessStatus(process.Key, true);
worker.Execute(Executor.sender.Navision, process.Key); //
ChangeProcessStatus(process.Key, false);
WriteToFile(process.Key + " Sync Finished at " + DateTime.Now);
}
}
protected override void OnStop()
{
WriteToFile("Service stopped at " + DateTime.Now);
}
private void ChangeProcessStatus(string key, bool status)
{
processStatus[key] = status;
}
public void WriteToFile(string Message)
{
string path = AppDomain.CurrentDomain.BaseDirectory + "\\data\\logs";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
string filepath = AppDomain.CurrentDomain.BaseDirectory + "\\data\\logs\\ServiceLog_" + DateTime.Now.Date.Day + " " + month + ".log";
if (!File.Exists(filepath))
{
using (StreamWriter sw = File.CreateText(filepath))
{
sw.WriteLine(Message);
}
}
else
{
using (StreamWriter sw = File.AppendText(filepath))
{
sw.WriteLine(Message);
}
}
}
}
}
But if i remove the lines
using Drone.Engine;
The service is starting successfully. Why am i unable to use it in the service?
The dll is present in the same directory. I have used the release build for installing. Still this issue.

Previously i was using filepaths like
filePath=#"data\log";
This was working fine in my application. But when i reference it to my windows service, i was getting System.IO.DirectoryNotFoundException error.
I changed the filepath to
filepath=AppDomain.CurrentDomain.BaseDirectory + "\\data\\logs";
It worked for both my service and application.

Related

How to convert a script(Capture Packets and save it to log file) into Window Service?

I want to write a window service for keep capturing the network traffic and save the packets info into a log file, but I can't start it.
"Error 1064: An exception occurred in the service when handling the control request."
References:
Capturing And Parsing Packets
Save Output to Log
Create Window Service
Here's the code for Windows Service(failed):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using CapturingAndParsingPackets;
using PacketDotNet;
using SharpPcap;
namespace CaptureService
{
public partial class Service1 : ServiceBase
{
private static bool _stopCapturing;
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);//Get the desktop path
string filename = DateTime.Now.ToString("yyyy-MM-dd--HH-mm-ss");//Use date to name the file
public Service1()
{
InitializeComponent();
var devices = CaptureDeviceList.Instance; //Get the local devices
if (devices.Count < 1)
{
OnStop();
return;
}
}
protected override void OnStart(string[] args)
{
var devices = CaptureDeviceList.Instance; //Get the local devices
//set output type
var defaultOutputType = StringOutputType.Normal;
var outputTypeValues = Enum.GetValues(typeof(StringOutputType));
StringOutputType selectedOutputType = defaultOutputType;
int userSelectedOutputType;
userSelectedOutputType = 3;
selectedOutputType = (StringOutputType)userSelectedOutputType;
//read local device
var device = devices[3];
//read packets
var readTimeoutMilliseconds = 1000;
device.Open(DeviceModes.Promiscuous, readTimeoutMilliseconds);
//set filter
string filter = "host 192.168.0.212";
device.Filter = filter;
PacketCapture e;
var status = device.GetNextPacket(out e);
var rawCapture = e.GetPacket();
// use PacketDotNet to parse this packet and print out
// its high level information
var p = Packet.ParsePacket(rawCapture.GetLinkLayers(), rawCapture.Data);
// Create a log file to desktop and write the log into the log file
using (StreamWriter w = File.AppendText(path + "\\" + filename + ".log"))
{
Log(p.ToString(selectedOutputType) + p.PrintHex(), w);
}
device.Close();
}
public static void Log(string logMessage, TextWriter txtWriter)
{
try
{
txtWriter.Write("\r\nLog Entry : ");
txtWriter.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
DateTime.Now.ToLongDateString());
txtWriter.WriteLine();
txtWriter.WriteLine(logMessage);
txtWriter.WriteLine("============================================================================================================");
}
catch (Exception)
{
}
}
protected override void OnStop()
{
using (StreamWriter w = File.AppendText(path + "\\" + filename + ".log"))
{
Log("Service is stopped at " + DateTime.Now, w);
}
}
}
}
And Here is the script for just running it in VS(works fine):
using System;
using PacketDotNet;
using SharpPcap;
using System.IO;
using System.Reflection;
using log4net;
using log4net.Config;
namespace CapturingAndParsingPackets
{
class MainClass
{
// used to stop the capture loop
private static bool _stopCapturing;
public static void Main(string[] args)
{
// Print SharpPcap version
var ver = SharpPcap.Pcap.SharpPcapVersion;
Console.WriteLine("PacketDotNet example using SharpPcap {0}", ver);
// Retrieve the device list
var devices = CaptureDeviceList.Instance;
// If no devices were found print an error
if (devices.Count < 1)
{
Console.WriteLine("No devices were found on this machine");
return;
}
Console.WriteLine();
Console.WriteLine("The following devices are available on this machine:");
Console.WriteLine("----------------------------------------------------");
Console.WriteLine();
var i = 0;
// Print out the devices
foreach (var dev in devices)
{
/* Description */
Console.WriteLine("{0}) {1} {2}", i, dev.Name, dev.Description);
i++;
}
Console.WriteLine();
Console.Write("-- Please choose a device to capture: ");
Console.WriteLine();
Console.WriteLine("Output Verbosity Options");
Console.WriteLine("----------------------------------------------------");
Console.WriteLine();
var defaultOutputType = StringOutputType.Normal;
var outputTypeValues = Enum.GetValues(typeof(StringOutputType));
foreach (StringOutputType outputType in outputTypeValues)
{
Console.Write("{0} - {1}", (int)outputType, outputType);
if (outputType == defaultOutputType)
{
Console.Write(" (default)");
}
Console.WriteLine("");
}
Console.WriteLine();
Console.Write("-- Please choose a verbosity (or press enter for the default): ");
StringOutputType selectedOutputType = defaultOutputType;
int userSelectedOutputType;
//Fixed
userSelectedOutputType = 3;
selectedOutputType = (StringOutputType)userSelectedOutputType;
// Register a cancel handler that lets us break out of our capture loop
Console.CancelKeyPress += HandleCancelKeyPress;
//Fixed
var device = devices[3];
// Open the device for capturing
var readTimeoutMilliseconds = 1000;
device.Open(DeviceModes.Promiscuous, readTimeoutMilliseconds);
//filter host 192.168.0.212
//or you can set it to "filter = 'ip'; " for default
string filter = "host 192.168.0.212";
device.Filter = filter;
Console.WriteLine();
Console.WriteLine("-- Listening on {0}, hit 'ctrl-c' to stop...",
device.Name);
while (_stopCapturing == false)
{
PacketCapture e;
var status = device.GetNextPacket(out e);
// null packets can be returned in the case where
// the GetNextRawPacket() timed out, we should just attempt
// to retrieve another packet by looping the while() again
if (status != GetPacketStatus.PacketRead)
{
// go back to the start of the while()
continue;
}
var rawCapture = e.GetPacket();
// use PacketDotNet to parse this packet and print out
// its high level information
var p = Packet.ParsePacket(rawCapture.GetLinkLayers(), rawCapture.Data);
Console.WriteLine(p.ToString(selectedOutputType) + p.PrintHex());
Console.WriteLine("============================================================================================================");
using (StreamWriter w = File.AppendText("networkTraffic.log"))
{
Log(p.ToString(selectedOutputType), w);
Log(p.PrintHex(), w);
}
}
Console.WriteLine("-- Capture stopped");
// Print out the device statistics
Console.WriteLine(device.Statistics.ToString());
// Close the pcap device
device.Close();
}
static void Log(string logMessage, TextWriter txtWriter)
{
try
{
txtWriter.Write("\r\nLog Entry : ");
txtWriter.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
DateTime.Now.ToLongDateString());
txtWriter.WriteLine();
txtWriter.WriteLine(logMessage);
txtWriter.WriteLine("============================================================================================================");
}
catch (Exception)
{
}
}
static void HandleCancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
Console.WriteLine("-- Stopping capture");
_stopCapturing = true;
// tell the handler that we are taking care of shutting down, don't
// shut us down after we return because we need to do just a little
// bit more processing to close the open capture device etc
e.Cancel = true;
}
}
}
The error that shows in Event Viewer(1064):
Application: CaptureTrafficService.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.FileNotFoundException
at CaptureTrafficService.Service1.OnStart(System.String[])
at System.ServiceProcess.ServiceBase.ServiceQueuedMainCallback(System.Object)
at System.ServiceProcess.ServiceBase.Run(System.ServiceProcess.ServiceBase[])
at CaptureTrafficService.Program.Main()
Service cannot be started. System.IO.FileNotFoundException: Could not load file or assembly 'netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b1xxxxxxxxxxx' or one of its dependencies. The system cannot find the file specified.
File name: 'netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b1xxxxxxxxxxx'
at CaptureTrafficService.Service1.OnStart(String[] args)
at System.ServiceProcess.ServiceBase.ServiceQueuedMainCallback(Object state)
After I remove the while loop in OnStart method, It shows up another error(1053):
Application: CaptureTrafficService.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.FileNotFoundException
Exception Info: System.IO.FileNotFoundException
at CaptureService.Service1..ctor()
at CaptureService.Program.Main()
The answer by #Sam1916 might lessen the frustration of FileNotFoundException.
The "System.IO.FileNotFoundException" caught my attention - but missing info on what files.
As Windows services run in "their own context" the files referenced (Through "using") might not exists in a readable directory, hench "FileNotFoundException"
Is the logfile placed in a directory where your service credentials are allowed to write?
There are too many unnecessary references that may affect each other in the solution so that it will return a lot of errors & warnings when building it. Just add them one by one if it is necessary, rebuild it when you added a new reference(for checking the compatibility) and not just copying all of them to the solution.
Too many unnecessary references(Before)
Just add the references you need(After)
Here's the code that works with windows service:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using SharpPcap;
using PacketDotNet;
namespace Capture
{
public partial class Capture : ServiceBase
{
Timer timer = new Timer();
public Capture()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Log("Service started at " + DateTime.Now);
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
//timer.Interval = 5000;
timer.Enabled = true;
}
protected override void OnStop()
{
Log("Service is stopped at " + DateTime.Now);
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
var devices = CaptureDeviceList.Instance;
//set output type
var defaultOutputType = StringOutputType.Normal;
StringOutputType selectedOutputType = defaultOutputType;
int userSelectedOutputType;
userSelectedOutputType = ? ;//? = 0-3
selectedOutputType = (StringOutputType)userSelectedOutputType;
//read local device
var device = devices[?];//? is mean num 0-4 or more(depends on your device)
//read packets
var readTimeoutMilliseconds = 1000;
device.Open(DeviceModes.Promiscuous, readTimeoutMilliseconds);
PacketCapture d;
var status = device.GetNextPacket(out d);
var rawCapture = d.GetPacket();
var p = Packet.ParsePacket(rawCapture.LinkLayerType, rawCapture.Data);
Log(p.ToString(selectedOutputType) +p.PrintHex());//write to log file
device.Close();
}
public static void Log(string logMessage)
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);+ "\\Logs" ;
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
string filepath =Environment.GetFolderPath(Environment.SpecialFolder.Desktop); + "\\Logs\\ServiceLog_" +
DateTime.Now.Date.ToShortDateString().Replace('/','_') + ".log";
using (StreamWriter sw = File.AppendText(filepath))
{
sw.WriteLine(logMessage);
sw.WriteLine("============================================================================================================");
}
}
}
}

Continuous Async Ping inside a Windows Service

I need to monitor a list of hosts continuously. After N seconds, i need to check the list again. So, I tried to use the async ping inside a Windows Service.
I tried to follow tips from other posts related to the topic, but always my service stops shortly after starting it.
There are a problem with await in "OnElapsedTime" function.
Any one have an idea what is wrong? Bellow my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Net.NetworkInformation;
namespace PingAsyncService
{
public partial class HyBrazil_Ping : ServiceBase
{
Timer timer = new Timer();
List<string> IPList = new List<string>(); //List of IPs
public HyBrazil_Ping()
{
IPList.Add("192.168.0.1");
IPList.Add("192.168.0.254");
InitializeComponent();
}
protected override void OnStart(string[] args)
{
WriteToFile("Service is started at " + DateTime.Now);
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 5000; //number in miliseconds
timer.Enabled = true;
}
protected override void OnStop()
{
WriteToFile("Service is stopped at " + DateTime.Now);
}
private async void OnElapsedTime(object source, ElapsedEventArgs e)
{
//WriteToFile("Service is recall at " + DateTime.Now);
var ResultList = await PingAsync();
foreach(PingReply reply in ResultList)
{
WriteToFile(reply.Address.ToString() + ";" + reply.Status.ToString());
}
}
private async Task<PingReply> PingAndProcessAsync(Ping pingSender, string ip)
{
var result = await pingSender.SendPingAsync(ip, 2000);
return result;
}
private async Task<List<PingReply>> PingAsync()
{
Ping pingSender = new Ping();
var tasks = IPList.Select(ip => PingAndProcessAsync(pingSender, ip));
var results = await Task.WhenAll(tasks);
return results.ToList();
}
public void WriteToFile(string Message)
{
string path = AppDomain.CurrentDomain.BaseDirectory + "\\Logs";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
string filepath = AppDomain.CurrentDomain.BaseDirectory + "\\Logs\\ServiceLog_" + DateTime.Now.Date.ToShortDateString().Replace('/', '_') + ".txt";
if (!File.Exists(filepath))
{
// Create a file to write to.
using (StreamWriter sw = File.CreateText(filepath))
{
sw.WriteLine(Message);
}
}
else
{
using (StreamWriter sw = File.AppendText(filepath))
{
sw.WriteLine(Message);
}
}
}
}
}
Thanks a lot!
In one of the comments you mentioned the error message as
"An asynchronous call is already in progress. It must be completed or canceled before you can call this method."
Chances are, the Ping object does not let simultaneous asynchronous calls.
Using a new Ping object everytime, on each call, might help as below.
private async Task<List<PingReply>> PingAsync()
{
// Ping pingSender = new Ping();
var tasks = IPList.Select(ip =>
{
using (var p= new Ping())
{
return PingAndProcessAsync(p, ip);
}
});
var results = await Task.WhenAll(tasks);
return results.ToList();
}

Crash in MouseKeyHook

can some one take a look to my C# source that has a crash issue? The program is supposed to omit unwanted double clicks the mouse sometimes sends and it works but after a while using the program it crashes.
The line that crashes:
Application.Run(new TheContext());
This is the error code:
An unhandled exception of type 'System.NullReferenceException' occurred in Gma.System.MouseKeyHook.dll
I'm using Visual studio community 2017
Source:
program.cs:
https://pastebin.com/AX9VRi00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
namespace MouseFixer
{
static class Program
{
static Mutex pmu;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// Console.WriteLine("Hello");
try
{
Mutex.OpenExisting("MouseFixer");
MessageBox.Show("MouseFixer is already running", "", MessageBoxButtons.OK, MessageBoxIcon.Stop);
return;
}
catch
{
pmu = new Mutex(true, "MouseFixer");
}
Application.Run(new TheContext());
}
}
}
thecontext.cs:
https://pastebin.com/G1cNzj4d
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Gma.System.MouseKeyHook;
using System.Diagnostics;
namespace MouseFixer
{
public class TheContext : ApplicationContext
{
// https://stackoverflow.com/questions/30061813/intercept-mouse-click
StringBuilder logText;
long lastClickTime;
long lastMouseUp;
bool ignoreClick = false;
void writeLog(string msg)
{
logText.Append(msg + Environment.NewLine);
File.AppendAllText("log.txt", logText.ToString());
logText.Clear();
}
bool errorShown = false;
void errorMsg(string str)
{
if(!errorShown)
MessageBox.Show(str);
errorShown = true;
}
long getTime()
{
return DateTimeOffset.Now.ToUnixTimeMilliseconds();
}
public TheContext()
{
Application.ApplicationExit += new EventHandler(this.OnExit);
logText = new StringBuilder();
lastClickTime = getTime();
lastMouseUp = getTime();
Hook.GlobalEvents().MouseDownExt += async (sender, e) =>
{
if (e.Button == MouseButtons.Left)
{
// e.Handled = true;
// writeLog("Handling click DOWN! " + e.Delta);
long lmu = (getTime() - lastMouseUp);
if (lmu < 10)
{
Debug.WriteLine("Too fast click - ignoring " + (getTime() - lastMouseUp) + Environment.NewLine);
e.Handled = true;
ignoreClick = true;
}
long lct = getTime() - lastClickTime;
lastClickTime = getTime();
Debug.WriteLine("MouseDOWN " + lct + " ( " + lmu + " ) " + Environment.NewLine);
}
};
Hook.GlobalEvents().MouseUpExt += async (sender, e) =>
{
if (e.Button == MouseButtons.Left)
{
if (!ignoreClick)
{
// e.Handled = true;
// writeLog("Handling click UP! " + e.Delta);
long lct = getTime() - lastClickTime;
lastClickTime = getTime();
Debug.WriteLine("MouseUP " + lct + Environment.NewLine);
lastMouseUp = getTime();
}
else
{
Debug.WriteLine("Ignoring click " + Environment.NewLine);
e.Handled = true;
ignoreClick = false;
}
}
};
}
private void OnExit(object sender, EventArgs e)
{
// File.AppendAllText("log.txt", logText.ToString());
}
}
}

Real time event handler in ZKemKeeper library not responding

I have created a Windows Service to fetch attendance by using real time event from a fingerprint device using Interop.zkemkeeper library. In service Machine is successfully connected but the service is not responding to the OnAttTransactionEx real time event means that after succesfull connection to machine attendance is not fetched using OnAttTransactionEx event. I don't know what is the problem.
Here's the code for Windows Service:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Timers;
using System.IO;
using zkemkeeper;
using System.Threading;
using System.Windows.Forms;
namespace WindowsService1
{
public partial class Service1 : ServiceBase
{
// private System.Timers.Timer timer1 = null;
string filePath = #"E:\file1.txt";
bool connSatus = false;
CZKEMClass axCZKEM1;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
/* timer1 = new Timer();
this.timer1.Interval = 10000;
this.timer1.Elapsed += new System.Timers.ElapsedEventHandler(this.timer1_Tick);
timer1.Enabled = true;
*/
axCZKEM1 = new zkemkeeper.CZKEMClass();
Thread createComAndMessagePumpThread = new Thread(() =>
{
connSatus = axCZKEM1.Connect_Net("192.169.9.34", 4370);
using (StreamWriter writer = new StreamWriter(filePath, true))
{
writer.WriteLine("Machine is connected on" + "Date :" + DateTime.Now.ToString() + "status" + connSatus);
writer.WriteLine(Environment.NewLine + "-----------------------------------------------------------------------------" + Environment.NewLine);
}
if (connSatus == true)
{
this.axCZKEM1.OnAttTransactionEx -= new zkemkeeper._IZKEMEvents_OnAttTransactionExEventHandler(axCZKEM1_OnAttTransactionEx);
if (axCZKEM1.RegEvent(1, 65535))//Here you can register the realtime events that you want to be triggered(the parameters 65535 means registering all)
{
this.axCZKEM1.OnAttTransactionEx += new zkemkeeper._IZKEMEvents_OnAttTransactionExEventHandler(axCZKEM1_OnAttTransactionEx);
using (StreamWriter writer = new StreamWriter(filePath, true))
{
writer.WriteLine("finger print Event is registered... ");
writer.WriteLine(Environment.NewLine + "-----------------------------------------------------------------------------" + Environment.NewLine);
}
}
}
Application.Run();
});
createComAndMessagePumpThread.SetApartmentState(ApartmentState.STA);
createComAndMessagePumpThread.Start();
}
public void axCZKEM1_OnAttTransactionEx(string sEnrollNumber, int iIsInValid, int iAttState, int iVerifyMethod, int iYear, int iMonth, int iDay, int iHour, int iMinute, int iSecond, int iWorkCode)
{
// if (OnAttTransactionEx != null) OnAttTransactionEx(sEnrollNumber, iIsInValid, iAttState, iVerifyMethod, iYear, iMonth, iDay, iHour, iMinute, iSecond, iWorkCode, axCZKEM1.MachineNumber, Tag);
using (StreamWriter writer = new StreamWriter(filePath, true))
{
writer.WriteLine(" OnAttTrasactionEx Has been Triggered,Verified OK on" + "Date :" + "Enrollnumber" + sEnrollNumber + DateTime.Now.ToString());
writer.WriteLine(Environment.NewLine + "-----------------------------------------------------------------------------" + Environment.NewLine);
}
}
protected override void OnStop()
{
// timer1.Enabled = false;
this.axCZKEM1.OnAttTransactionEx -= new zkemkeeper._IZKEMEvents_OnAttTransactionExEventHandler(axCZKEM1_OnAttTransactionEx);
axCZKEM1.Disconnect();
}
private void timer1_Tick(object sender, EventArgs e)
{
using (StreamWriter writer = new StreamWriter(filePath, true))
{
writer.WriteLine("Message is running on" + "Date :" + DateTime.Now.ToString());
writer.WriteLine(Environment.NewLine + "-----------------------------------------------------------------------------" + Environment.NewLine);
}
}
}
}
corret version is that
protected override void OnStart(string[] args)
{
Thread createComAndMessagePumpThread = new Thread(() =>
{
axCZKEM1 = new zkemkeeper.CZKEMClass();
connSatus = axCZKEM1.Connect_Net("192.169.9.34", 4370);
using (StreamWriter writer = new StreamWriter(filePath, true))
{
writer.WriteLine("Machine is connected on" + "Date :" + DateTime.Now.ToString() + "status" + connSatus);
writer.WriteLine(Environment.NewLine + "-----------------------------------------------------------------------------" + Environment.NewLine);
}
if (connSatus == true)
{
this.axCZKEM1.OnAttTransactionEx -= new zkemkeeper._IZKEMEvents_OnAttTransactionExEventHandler(axCZKEM1_OnAttTransactionEx);
if (axCZKEM1.RegEvent(1, 65535))//Here you can register the realtime events that you want to be triggered(the parameters 65535 means registering all)
{
this.axCZKEM1.OnAttTransactionEx += new zkemkeeper._IZKEMEvents_OnAttTransactionExEventHandler(axCZKEM1_OnAttTransactionEx);
using (StreamWriter writer = new StreamWriter(filePath, true))
{
writer.WriteLine("finger print Event is registered... ");
writer.WriteLine(Environment.NewLine + "-----------------------------------------------------------------------------" + Environment.NewLine);
}
}
}
Application.Run();
});
createComAndMessagePumpThread.SetApartmentState(ApartmentState.STA);
createComAndMessagePumpThread.Start();
}

My C# multi-threaded console application seems to not be multithreaded

Here's my C# console program that uses Powerpoint to convert ppt files to folders of pngs. This is supposed to be an automated process that runs on its own server.
I expect that as soon as a thread creates an image from a file, it should immediately remove the images and the source file.
The actual behavior is that, if five threads are running, it'll wait for five folders of images to be created before any thread can move any files. I'm able to see the images being created, and compare that with the Console readout, so I can see that a thread isn't trying to move the file.
Only after all the other threads have made their images, will any thread try to move the files. I suspect this is wrong.
This is an Amazon EC2 Medium instance, and it appears to max out the CPU, so five threads might be too much for this.
I also find that I can hardly use Windows Explorer while this program is running.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using Microsoft.Office.Core;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using System.Diagnostics;
using System.Timers;
namespace converter
{
class Program
{
public static int threadLimit=0;
public static int currThreads = 0;
static void Main(string[] args)
{
var inDir = args[0];
var outDir = args[1]+"\\";
var procDir = args[2]+"\\";
Int32.TryParse(args[3],out threadLimit);
Thread[] converterThreads = new Thread[threadLimit];
while (true)
{
System.Threading.Thread.Sleep(1000);
var filePaths = Directory.GetFiles(inDir, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".pptx") && !s.Contains("~$") || s.EndsWith(".ppt") && !s.Contains("~$"));
var arrPaths = filePaths.ToArray();
for(var i=0; i< arrPaths.Length; i++)
{
if (currThreads < threadLimit && currThreads < arrPaths.Length)
{
Console.WriteLine("currThreads= " + currThreads + " paths found= " + arrPaths.Length);
try
{
var fileNameWithoutExtension = arrPaths[currThreads].Replace(inDir, "").Replace(".pptx", "").Replace(".ppt", "").Replace("\\", "");
var filenameWithExtension = arrPaths[currThreads].Substring(arrPaths[currThreads].LastIndexOf("\\") + 1);
var dir = arrPaths[currThreads].Replace(".pptx", "").Replace(".ppt", "");
Conversion con = new Conversion(arrPaths[currThreads], dir, outDir, procDir, filenameWithExtension, fileNameWithoutExtension);
converterThreads[i] = new Thread(new ThreadStart(con.convertPpt));
converterThreads[i].Start();
Console.WriteLine(converterThreads[i].ManagedThreadId + " is converting " + fileNameWithoutExtension);
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to convert {0} ", arrPaths[i]) + e);
}
}
}
for (var i = 0; i < converterThreads.Length; i++)
{
if (converterThreads[i] != null)
{
if (!converterThreads[i].IsAlive)
{
converterThreads[i].Abort();
converterThreads[i].Join(1);
Console.WriteLine("thread " + converterThreads[i].ManagedThreadId + " finished, "+currThreads+" remaining");
converterThreads[i] = null;
}
}
}
if (currThreads == 0)
{
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
}
}
}
class Logger{
static void toLog(String msg)
{
//TODO: log file
}
}
class Conversion{
static int numberOfThreads=0;
String input;
String output;
String outDir;
String process;
String nameWith;
String nameWithout;
int elapsedTime;
System.Timers.Timer time;
public Conversion(String input, String output, String outDir, String processDir, String nameWith, String nameWithout)
{
this.input = input;
this.output = output;
this.outDir = outDir;
process = processDir;
this.nameWith = nameWith;
this.nameWithout = nameWithout;
numberOfThreads++;
Console.WriteLine("number of threads running: " + numberOfThreads);
Program.currThreads = numberOfThreads;
time = new System.Timers.Timer(1000);
time.Start();
time.Elapsed += new ElapsedEventHandler(OnTimedEvent);
elapsedTime = 0;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
elapsedTime++;
}
public void convertPpt()
{
var app = new PowerPoint.Application();
var pres = app.Presentations;
try
{
var file = pres.Open(input, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoFalse);
file.SaveAs(output, Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType.ppSaveAsPNG, MsoTriState.msoTrue);
file.Close();
app.Quit();
Console.WriteLine("file converted " + input);
}
catch (Exception e)
{
Console.WriteLine("convertPpt failed");
}
moveFile();
moveDir();
}
public void moveFile()
{
Console.WriteLine("moving" + input);
try
{
System.Threading.Thread.Sleep(500);
Console.WriteLine(string.Format("moving {0} to {1}", input, process + nameWith));
if (File.Exists(process + nameWith))
{
File.Replace(input, process + nameWith, null);
}
else
{
File.Move(input, process + nameWith);
}
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to move the file {0} ", input) + e);
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
}
public void moveDir()
{
Console.WriteLine("moving dir " + output);
try
{
System.Threading.Thread.Sleep(500);
Console.WriteLine(string.Format("moving dir {0} to {1} ", output, outDir + nameWithout));
if (Directory.Exists(outDir + nameWithout))
{
Directory.Delete(outDir + nameWithout, true);
}
if (Directory.Exists(output))
{
Directory.Move(output, outDir + nameWithout);
}
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to move the directory {0} ", output) + e);
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
finally
{
numberOfThreads--;
Program.currThreads = numberOfThreads;
Console.WriteLine("took " + elapsedTime + "seconds");
}
}
}
}
Every 1000ms you get a list of files in inDir and potentially start a thread to process each file. You have very complex logic surrounding whether or not to start a new thread, and how to manage the lifetime of the thread.
The logic is too complex for me to spot the error without debugging the code. However, I would propose an alternative.
Have a single thread watch for new files and place the file path into a BlockingCollection of files for processing. That thread does nothing else.
Have N additional threads that retrieve file paths from the BlockingCollection and process them.
This is known as a Producer / Consumer pattern and is ideal for what you are doing.
The example code at the bottom of the linked MSDN page shows an implementation example.
On a side note, you are catching and swallowing Exception e3. Don't catch something you will not handle, it hides problems.

Categories