|
Indeed, but I'm only working with the OPs original code - yes, if it were my code, I'd add in terminating conditions. As I don't know what the OPs ultimate use case is here, I'm loathe to suggest this - I've just had to assume that the lock has a finite limit.
|
|
|
|
|
Pete O'Hanlon wrote: I've just had to assume that the lock has a finite
limit.
True. I don't know any more about his requirements than you. I just wanted to point out that it's not the ultimate solution for anyone else just scrounging for code.
Pete O'Hanlon wrote: I'm loathe to suggest this
Kinda makes you want to take a long shower, doesn't it?
|
|
|
|
|
Use the FileSystemWatcher, when it notifies you of a change put an entry on a queue with a retrieval time of 1 second (or 200ms or whatever is appropriate in the future), and have another thread which pulls things off that queue at the right time and actions them. In this case the action is 'read file, find text, replace, write file'. If it fails, re-queue it.
|
|
|
|
|
Based on the description, I believe this is what the OP has said he's done (all except for the pause bit).
|
|
|
|
|
Sorry for the delay responses! Just had a baby girl
Anyways let me explain. I'm setting up a multi-tenant quickbooks environment. The problem is as we probably all know is it wasn't really designed for multi-tenancy. Now everything works fine with what I have except the username is populated on a program level.
So in the ProgramData directory (All Users) there is a qbw.ini file that contains LASTUSERNAME=. Each time a user launches quickbooks it reads this information and prepopulated the username field for the company database login.
I don't want people seeing other peoples logins. Most just use Admin which isn't a big deal but some use their company name. So I don't want another company seeing that.
So my idea is to monitor that file for updates using a file system watcher and changing that value in the INI file to blank. So basically changing something like this: "LASTUSERNAME=Admin" to this: "LASTUSERNAME="
Quickbooks does not place a permanent lock on this file. So we don't have to worry about quickbooks locking it for a long period of time.
I'm trying suggestions as we speak. I'm adding an error count to stop the service if an exception happens so many times within a specific time period. Hopefully this will stop an overflow exception like you were talking about. I can make something to restart the service ever so often.
Not the best plan but so far thats what I got!
|
|
|
|
|
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.
|
|
|
|
|