|
Alright so here is what I ended up with. It seems to work... catches the IO exceptions and continues running. So far it is working good enough for me
using System;
using System.Diagnostics;
using System.IO;
using System.ServiceProcess;
using System.Text;
using System.Threading;
namespace QBiniMonitor
{
public partial class QBMonitor : ServiceBase
{
FileSystemWatcher watcher2012;
FileSystemWatcher watcher2011;
string QB2012 = Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%") + @"\Intuit\QuickBooks 2012\";
string QB2011 = Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%") + @"\Intuit\QuickBooks 2011\";
enum Version
{
QB2011,
QB2012
}
public QBMonitor()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
StartNewWatcher(Version.QB2011);
StartNewWatcher(Version.QB2012);
}
private void StartNewWatcher(Version watcherVersion)
{
if (watcherVersion == Version.QB2011)
{
watcher2011 = new FileSystemWatcher();
watcher2011.Path = QB2011;
watcher2011.Filter = "qbw.ini";
watcher2011.NotifyFilter = NotifyFilters.LastWrite;
watcher2011.Changed += new FileSystemEventHandler(watcher_Changed);
StartStopWatcher(Version.QB2011, true);
}
else if (watcherVersion == Version.QB2012)
{
watcher2012 = new FileSystemWatcher();
watcher2012.Path = QB2012;
watcher2012.Filter = "qbw.ini";
watcher2012.NotifyFilter = NotifyFilters.LastWrite;
watcher2012.Changed += new FileSystemEventHandler(watcher_Changed);
StartStopWatcher(Version.QB2012, true);
}
}
private void watcher_Changed(object sender, FileSystemEventArgs e)
{
FileSystemWatcher watcher = sender as FileSystemWatcher;
if (watcher.Path == QB2012)
StartStopWatcher(Version.QB2012, false);
else if (watcher.Path == QB2011)
StartStopWatcher(Version.QB2011, false);
bool saveFile = false;
string oldValue = string.Empty;
StringBuilder sb = new StringBuilder();
try
{
using (FileStream fs = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read))
{
using (StreamReader sr = new StreamReader(fs))
{
while (sr.Peek() >= 0)
{
string currentLine = sr.ReadLine();
if (currentLine.StartsWith("LASTUSERNAME="))
{
if (!currentLine.Equals("LASTUSERNAME=Admin"))
{
sb.AppendLine("LASTUSERNAME=Admin");
oldValue = currentLine;
saveFile = true;
}
else
sb.AppendLine(currentLine);
}
else
sb.AppendLine(currentLine);
}
}
}
}
catch (Exception ex)
{
EventLog.WriteEntry("QBiniMonitor", "watcher_Changed::: " + ex.ToString(), EventLogEntryType.Error);
}
if (saveFile)
{
if (watcher.Path == QB2012)
WriteFile(Version.QB2012, e.FullPath, sb, oldValue, 1);
else if (watcher.Path == QB2011)
WriteFile(Version.QB2011, e.FullPath, sb, oldValue, 1);
}
else
{
if (watcher.Path == QB2012)
StartStopWatcher(Version.QB2012, true);
else if (watcher.Path == QB2011)
StartStopWatcher(Version.QB2011, true);
}
}
private static readonly object SyncLock = new object();
private void WriteFile(Version watcherVersion, string file, StringBuilder sb, string oldValue, int retryCount)
{
if (retryCount < 5)
{
try
{
using (StreamWriter sw = new StreamWriter(file, false))
{
sw.Write(sb.ToString());
}
EventLog.WriteEntry("QBiniMonitor", "Version: " + watcherVersion.ToString() + ". The value for the last username was cleared. The previous value was: " + oldValue, EventLogEntryType.Information);
StartStopWatcher(watcherVersion, true);
}
catch (IOException)
{
lock (SyncLock)
{
EventLog.WriteEntry("QBiniMonitor", "Version: " + watcherVersion.ToString() + ". File was locked. Waiting 2 seconds and trying again. Retry number: " + retryCount);
Monitor.Wait(SyncLock, 2000);
}
retryCount = retryCount + 1;
WriteFile(watcherVersion, file, sb, oldValue, retryCount);
}
}
else
{
EventLog.WriteEntry("QBiniMonitor", "WriteFile::: " + "Retry limit of 5 was reached while trying to change the data in the file. (Because the file was locked)", EventLogEntryType.Warning);
StartStopWatcher(watcherVersion, true);
}
}
private void StartStopWatcher(Version watcherVersion, bool start)
{
try
{
switch (watcherVersion)
{
case Version.QB2011:
if (start)
{
watcher2011.EnableRaisingEvents = true;
}
else
{
watcher2011.EnableRaisingEvents = false;
}
break;
case Version.QB2012:
if (start)
{
watcher2012.EnableRaisingEvents = true;
}
else
{
watcher2012.EnableRaisingEvents = false;
}
break;
default:
break;
}
}
catch (IOException ex)
{
EventLog.WriteEntry("QBiniMonitor", "StartStopWatcher::: " + ex.ToString(), EventLogEntryType.Error);
Stop();
}
catch (Exception ex)
{
EventLog.WriteEntry("QBiniMonitor", "StartStopWatcher::: " + ex.ToString(), EventLogEntryType.Error);
Stop();
}
}
protected override void OnStop()
{
if (watcher2011 != null)
{
watcher2011.EnableRaisingEvents = false;
watcher2011.Dispose();
}
if (watcher2012 != null)
{
watcher2012.EnableRaisingEvents = false;
watcher2012.Dispose();
}
}
}
}
|
|
|
|
|
I have a C# 2010 console application where I need to create a setup and deployment project for it. I do not have the setup and deployment projects in the visual studio.net 2010 application I am using. I need to find the install templates.
Can you tell me where I can find the setup and deployment project install templates so I can add them to my solution ide to work with?
|
|
|
|
|
You should find them in the Other Projects ( Project Templates )
Create a new Project of type (Other Projects - > Setup and Deployment -> VS Installer) ...
Regards,
Senthil Kumar
|
|
|
|
|
I do not have a Create a new Project of type (Other Projects - > Setup and Deployment -> VS Installer). I am somehow missing the templates.
|
|
|
|
|
If you have an Express version of Visual Studio you won't have it.
|
|
|
|
|
Don't bother. The Setup and Deployment projects were killed off in VS2012 anyway so you're going after legacy technology that, lets be honest here, sucked!
You can use any number of other tools that do a better job and are eaier to use, such as Inno Setup, Advanced Installer, InstallShield LE, WiX, ...
|
|
|
|
|
Hi everyone
which one of these way is correct?why?
Matrix m=new Matrix();
Rectangle rect=new Rectangle(0,0,10,10);
PointF[] point=
{
....
};
Warp(point, rect, m, WarpMode.Perspective,0F);
or
Warp(new PointF[]{....}, new CRect(0,10,10,10), new Matrix(), WarpMode.Perspective,0F);
|
|
|
|
|
These are the overloads as defined[^] in the framework;
GraphicsPath.Warp (PointF[], RectangleF)
GraphicsPath.Warp (PointF[], RectangleF, Matrix)
GraphicsPath.Warp (PointF[], RectangleF, Matrix, WarpMode)
GraphicsPath.Warp (PointF[], RectangleF, Matrix, WarpMode, Single)
Did that answer your question?
Bastard Programmer from Hell
if you can't read my code, try converting it here[^]
|
|
|
|
|
No I didnt, I want to know can I use of this code or not?
Warp(new PointF[]{....}, new CRect(0,10,10,10), new Matrix(), WarpMode.Perspective,0F);
|
|
|
|
|
They are both syntactically correct. However, the first option is easier to debug when things start to go wrong.
One of these days I'm going to think of a really clever signature.
|
|
|
|
|
Thank you Richard.
|
|
|
|
|
I want to keep some of my classes in library files and load them during runtime. I can load the assemblies and everything works fine. However, I don't find any function that will close or unload the assembly after a method is done using the assembly.
If the function is called several times, the assembly loading will be done multiple times. Without any function to unload it, can it cause any problem in application some times?
I'm now beginning the project so I would like to know the right approach and follow it. I would like to know before I start my project as I do not want to face any problems in the middle of the project. Please help and thanks in advance.
|
|
|
|
|
Dan_K wrote: If the function is called several times, the assembly loading will be done multiple times.
Why? Just add in a boolean that's set when it's loaded the first time, and check it before you load the assembly. That way the logic is executed only once, eliminating the need to know how often the assembly is in memory.
FWIW; it's loaded into memory once, and remains there. There's no unloading, unless you put everything in a separate AppDomain.
Bastard Programmer from Hell
if you can't read my code, try converting it here[^]
|
|
|
|
|
Thanks! But does the AppDomain check whether it has already been loaded so that it does not load again for consecutive calls? I'm using .net framework 4.0.
|
|
|
|
|
Dan_K wrote: But does the AppDomain check whether it has already been loaded so that it does not load again for consecutive calls?
Dunno, you'd have to check the documentation for that. Just add in the check yourself, it's simply a matter of setting and checking a boolean to avoid the question in the first place - I wouldn't waste time on finding out.
Bastard Programmer from Hell
if you can't read my code, try converting it here[^]
|
|
|
|
|
Presumably you are referring to reflection in that you are loading the type yourself.
Per your basic description you should structure your code such that the assembly, and even the class is only loaded once. Once loaded you create instances from that class.
Dan_K wrote: I do not want to face any problems in the middle of the project
Better make sure that you do not need to unload it while the app is running since that is a different problem.
|
|
|
|
|
Dan_K wrote: If the function is called several times, the assembly loading will be done
multiple times
An assembly is only ever loaded once. There is no such thing as unloading it unless 1) you tear down the entire process into which it was loaded or 2) it was loaded into an AppDomain and you tear down the AppDomain.
Really, by trying to load and unload assemblies, you're creating FAR more complexity for your application. What if you unloaded an assembly that your code still needed?? BOOM! Exception! Good luck with this.
|
|
|
|
|
If you have the need for unloading assemblies then you have to load them in a dedicated AppDomain you will create first.
The advantages is that you can kill the newly created AppDomain (unloading assemblies) and other advantage is that if one assembly you load is "rotten" then you are not damaging the primary AppDomain.
The drawback is the only basic option to communicate between appdomain is remoting.
If you are looking for some kind of plug-in mechanism then have a look at ms Managed Extensibility Framework (MEF). You'll find good articles on CP about it.
|
|
|
|
|
Guirec Le Bars wrote: that if one assembly you load is "rotten" then you are not damaging the primary AppDomain.
That is true only to a limited extent. For example a bad assembly could still cause a out of memory error or a VM exit.
|
|
|
|
|
Do you really need to 'load them at runtime' (i.e. dynamically using Assembly.Load)? You only need to do that if you want a plugin based architecture. Simply linking to the DLLs at compile time should be sufficient in most cases.
If you do, you should implement some sort of lazy loading wrapper which loads an assembly only if it needs it. Though I think Assembly.Load probably already does that for you internally (don't quote me on that though).
You can only unload assemblies if they're loaded into separate AppDomains, which has serious implications for communication between modules.
|
|
|
|
|
When I try to click a button programmatically using .performClick() it only works when the button is in the same class
// this works
this.buttonStart.PerformClick();
But if I try to use the perform click outside the class it doesn't work
// this doesn' work
FormCalendarCS FCCS = new FormCalendarCS();
FCCS.buttonStart.PerformClick();
However if I use the following code I can access the button's method as follows, but doesn't click the button:
// this works
FCCS.buttonStart_Click(sender, e);
Why is this so, and how do I click on the button in another class.
I appreciate any help, thanks in advance.
Mihael
|
|
|
|
|
It seems like you have made buttonStart_Click public static in your FormCalendarCS class which is why you can access it (probably not a good idea!), whereas buttonStart is an instance created in the designer of your FormCalendarCS (exactly as it should be, check the contents of the designer.cs file).
Creating a new instance of the form will not get you the original button, just a new one on a new form that you haven't made visible so you will never see it.
First of all, change buttonStart_Click to private void buttonStart_Click(object sender, EventArgs e) , there is no valid reason to have it any other way IMO, and if you have changed it, set the access modifier on buttonStart back to private .
Inside FormCalendarCS create this method:
public void ButtonStartPerformClick()
{
buttonStart.PerformClick();
}
Inside your form where you first show your FormCalendarCS instance, add a field:
private FormCalendarCS formCalendarCS;
Before you show it, save the instance to the field.
formCalendarCS = new FormCalendarCS();
formCalendarCS.Show();
Now whenever you want to perform the click, just call:
formCalendarCS.ButtonStartPerformClick();
If the relationships between your classes/forms are more complex, you will need to route the method call(s) appropriately and you may need to use events too if you need to call back up the chain.
Your problem boils down to not understanding instance vs static objects and methods. These are a fundemental part of any OOP language including C# so I suggest some study on this area.
|
|
|
|
|
Thanks Dave,
I took your advice and did as you suggested, however, the button isn't static but was changed to public. I changed it back to private and accessed the button as you said. I also understand what you mean by a new instance of that class, I seem to forget that as I have did that more than once, only to realize my mistake.
Michael
|
|
|
|
|
I've never found a reason to use PerformClick, ever.
The code you put in the event handler really needs to be moved to it's own method. Then you can call it from the button Click event handler or from any outside caller without even touching the button.
|
|
|
|
|
I've never had a reason to use it either - the only advantage is it actually performs the click and so raises any other handlers attached to the Button 's Click event whereas calling the handling code would not do that.
|
|
|
|
|