.Net4.0, Windows 7(64bit), C# Winform based application.
Here is the method writing event log. However, there isn't shown event log on MS Eventviewer. Do you have any idea ?
private static void WriteEventLogEntry(string message)
{
// Create an instance of EventLog
System.Diagnostics.EventLog eventLog = new System.Diagnostics.EventLog();
// Check if the event source exists. If not create it.
if (!System.Diagnostics.EventLog.SourceExists("TestProgram"))
{
System.Diagnostics.EventLog.CreateEventSource("TestProgram", "Application");
}
// Set the source name for writing log entries.
eventLog.Source = "TestProgram";
// Create an event ID to add to the event log
int eventID = 8;
// Write an entry to the event log.
eventLog.WriteEntry(message,
System.Diagnostics.EventLogEntryType.Information,
eventID);
// Close the Event Log
eventLog.Close();
}
}
EDIT:
I have changed the code below. I can see event log without running as administrator. I have one more question. There are two log such as "Log 1" and "Log 2". I can see "Log 1" on viewer. However, I can't see "Log 2". Do you have any idea ?
using System.Diagnostics;
namespace ImageDelegateSample
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MdiForm mainForm = null;
try
{
bool createdNew;
Mutex dup = new Mutex(true, "ImageDelegateSample", out createdNew);
if (createdNew)
{
// Log 1
WriteEventLogEntry("Loading", EventLogEntryType.Information);
mainForm = new MdiForm();
Application.Run(mainForm);
// Log 2
WriteEventLogEntry("Done Loading", EventLogEntryType.Information);
}
else
{
MessageBox.Show("already running.");
}
}
catch (Exception e)
{
// You probably want something a little more sophisticated than this
MessageBox.Show(e.Message, "An exception occurred:", MessageBoxButtons.OK, MessageBoxIcon.Error);
HandleError(e);
System.Environment.Exit(0);
}
}
static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
HandleError(e.Exception);
}
internal static void HandleError(Exception e)
{
string message = e.Message + "\n\n";
if (e.InnerException != null)
message += "Inner exception:\n" + e.InnerException.Message + "\n\n";
message += e.StackTrace;
MessageBox.Show(message, "An error has occurred:");
}
private static readonly string EventLogName = "Application";
private static readonly string EventLogSource = "ImageDelegateSample.exe";
private static void WriteEventLogEntry(string message, EventLogEntryType type)
{
// In the only function that does something
if (!EventLog.Exists(EventLogName))
{
EventLog.CreateEventSource(EventLogSource, EventLogName);
return;
}
else
{
// This doesn't write anything
EventLog.WriteEntry(EventLogSource,
message,
type);
}
}
}
}
Related
I'm using this code to open an access database :
public partial class Start_Baseet : System.Windows.Forms.Form
{
string MyFile = Environment.CurrentDirectory + "\\Baseet.accde";
Microsoft.Office.Interop.Access.Application AccApp = new Microsoft.Office.Interop.Access.Application();
public Start_Baseet()
{
InitializeComponent();
}
public void OpenDb()
{
AccApp.Visible = true;
AccApp.OpenCurrentDatabase(MyFile, false, "017014a");
AccApp.RunCommand(AcCommand.acCmdAppMaximize);
// AccApp.Activate();
}
}
private void Start_Basset_Load(object sender, EventArgs e)
{
try
{
OpenDb();
}
catch
{
AccApp.Quit();
MessageBox.Show("Something is missing", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
finally
{
this.Close();
System.Windows.Forms.Application.Exit();
System.Windows.Forms.Application.ExitThread();
// Process.GetCurrentProcess().CloseMainWindow();
}
The problem is the MSACCESS process is piling up in the running processes so I tried this :
//var prc = Process.GetProcessesByName("MSACCESS.EXE*32");
var prc = Process.GetProcessesByName("Microsoft Access");
if (prc.Length > 0)
{
MessageBox.Show("Access Found");
SetForegroundWindow(prc[0].MainWindowHandle);
}
else
{
AccApp.Visible = true;
AccApp.OpenCurrentDatabase(MyFile, false, "017014a");
AccApp.RunCommand(AcCommand.acCmdAppMaximize);
// AccApp.Activate();
}
}
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
But still with every time I use the code another MSACCESS process starts.
How can I fix this ?
Other point if I ran my app second time it will open a new instance of the same database can I activate the database if it is opened otherwise open a new instance of it ?
Thanks
Try this. This should catch users closing out Access as well through error catching. I'm sure it can be improved on but, I don't get a bunch of MSAccess.exe in the background from this code I wrote a while ago.
public partial class Form1 : Form
{
Microsoft.Office.Interop.Access.Application accApp = new Microsoft.Office.Interop.Access.Application();
private bool isFormClosed = false;
public Form1()
{
InitializeComponent();
OpenMicrosoftAccessFile(#"FileName");
Thread t = new Thread(new ThreadStart(CheckIfMSAccessExeIsRunning));
t.Start();
}
/// <summary>
/// The User Closed Out Access Cleanup.
/// </summary>
public void CheckIfMSAccessExeIsRunning()
{
int secondsToWait = 5*1000;
while(!isFormClosed)
{
if (accApp != null &&
accApp.Visible == false)
CloseMicrosoftAccessFile();
Thread.Sleep(secondsToWait);
}
CloseMicrosoftAccessFile();
}
private bool OpenMicrosoftAccessFile(string accessFileName)
{
try
{
if (accApp != null &&
!accApp.Visible)
{
CloseMicrosoftAccessFile();
}
if (accApp == null)
{
accApp = new Microsoft.Office.Interop.Access.Application();
accApp.OpenCurrentDatabase(accessFileName);
accApp.Visible = true;
}
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine((ex.InnerException != null) ? ex.InnerException : "");
CloseMicrosoftAccessFile();
return false;
}
}
private void CloseMicrosoftAccessFile()
{
try
{
if (accApp != null)
{
accApp.CloseCurrentDatabase();
accApp.Quit();
}
}
catch (Exception ex)
{
//Good chance there never was an Access exe.
Console.WriteLine(ex.Message);
Console.WriteLine((ex.InnerException != null) ? ex.InnerException : "");
}
finally
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(accApp);
accApp = null;
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
isFormClosed = true;
}
}
Also, if you still have processes running the Debugger or Visual Studio is probably holding onto it still. It would be good to test this from the release exe. If OpenMicrosoftAccessFile returns false you can try opening it up again but, this way ignores the error it caught.
I want to check if .dll, .png and .exe files exist before first app windows launches, but problem is I cant no matter how I try it just throws error in event viewer, instead my message.
My IsResourceExist Method:
private static bool IsResourceExist(string fileName)
{
var process = Process.GetCurrentProcess();
string path = process.MainModule.FileName.Replace("\\" + process.ProcessName + ".exe", "");
try
{
if (!File.Exists(Path.Combine(path, fileName)))
{
MessageBox.Show("Unable to load " + fileName + " library\nReinstall application and try again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
return true;
}
catch
{
return false;
}
}
Simple method nothing fancy, in normal situation(when file actually exist works fine)
private static bool CheckLibrarys()
{
if (!IsResourceExist("MyLib.dll")) return false;
//Other resources checking same way
return true;
}
This method checks all apps needed resources, also works on normal situation(when all files exist)
This I think very first code line called by app, works when files exist
public App()
{
if (!CheckLibrarys()) Environment.Exit(0);
}
When I delete MyLib.dll file in event viewer it throws:
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.FileNotFoundException at
myapp.App.CheckLibrarys() at myapp.App..ctor() at
myapp.App.Main()
Like for real is this somekind of .Net Framework joke? What I'm missing here?
EDIT 1:
Same situation even with OnStartup override
protected override void OnStartup(StartupEventArgs e)
{
if (!CheckLibrarys()) Environment.Exit(0);
base.OnStartup(e);
}
EDIT 2 extending #bic answer and still app does not launch and does not throw any error that mylib is misssing
private static bool CheckLibrarys()
{
if (!IsResourceExist("MyLib.dll")) { return false; }
else
{
if (!MyLib.Init.ReturnOnlyTrue())
{
MessageBox.Show("Wrong loaded library, reinstall application and try again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
}
//Other resources checking same way
return true;
}
In my MyLib Init class ReturnOnlyTrue() method look like this:
public static bool ReturnOnlyTrue()
{
return true;
}
If the dll is referenced in the project then it cannot be missing otherwise the project references cannot be resolved. If you remove it from the project references and simply load it at runtime then you shouldnt have this problem.
Here is a nice description of how the runtime resolves references. This is ultimately where the FileNotFound exception is coming from.
https://learn.microsoft.com/en-us/dotnet/framework/deployment/how-the-runtime-locates-assemblies
In order for you to capture the error when the application starts you can add error handling as follows.
namespace SO_Wpf
{
using System;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Threading;
public partial class App : Application
{
public App()
{
Current.DispatcherUnhandledException += this.AppDispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException += this.AppDomainUnhandledException;
}
private void AppDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
if (e.Exception.GetType() == typeof(FileNotFoundException))
{
if (!CheckLibrarys())
{
Current.Shutdown();
}
}
else
{
MessageBox.Show(e.Exception.Message);
}
}
private void AppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
if (e.ExceptionObject.GetType() == typeof(FileNotFoundException))
{
if (!CheckLibrarys())
{
Current.Shutdown();
}
}
else
{
MessageBox.Show(e.ExceptionObject.ToString());
}
}
private static bool CheckLibrarys()
{
if (!IsResourceExist("MyLib.dll"))
{
return false;
}
//Other resources checking same way
return true;
}
private static bool IsResourceExist(string fileName)
{
var process = Process.GetCurrentProcess();
var path = process.MainModule.FileName.Replace("\\" + process.ProcessName + ".exe", "");
try
{
if (!File.Exists(Path.Combine(path, fileName)))
{
MessageBox.Show("Unable to load " + fileName + " library\nReinstall application and try again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
return true;
}
catch
{
return false;
}
}
}
}
e.Exception.Message will give you the message or you can change the output altogether by checking the error and if its FileNotFoundException etc. tell the user and exit.
You can override OnStartup method of App.xaml. In this you can add your custom logic.
Maybe exception is coming form somewhere else. You can add a global exception handler and can see from where it is coming form.
public partial class App : Application
{
public App()
{
DispatcherUnhandledException += App_DispatcherUnhandledException;
}
private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
e.Handled = true;
MessageBox.Show(e.Exception.Message);
Environment.Exit(0);
}
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
if (!SomeCondition)
Application.Current.Shutdown();
}
}
I've been scratching my head on this one for a while now and despite looking for solutions, im not quite understanding the implementations (several answers on stack overflow have already been looked at)
My program loads a splash page when it is opened, during which it checks for a database connection. If there is a connection, the splash page closes and the main form loads, otherwise it provides an error message then closes completely.
public partial class StartupSplash : Form
{
ThreadStart th;
Thread thread;
public StartupSplash()
{
InitializeComponent();
th = new ThreadStart(DbAvaliable);
thread = new Thread(th);
thread.Start();
}
private void DbAvaliable()
{
Boolean result = false;
using (var connectiontest = new SqlConnection("myConnString"))
try
{
connectiontest.Open();
result = true;
}
catch (Exception ex)
{
result = false;
}
if (result)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainWindow());
}
else
{
MessageBox.Show("Unable to establish database connection. Please check your data connection and try again.");
}
}
}
I understand that I can't simply call this.Close() due to cross thread issues. I've read something about invoking methods, but im not too clear how to achieve the result above.
Initially I tried to use form load/shown events instead of alternate threads, but the image on the forms failed to load until after the messagebox had shown the error (rather than displaying, then running the connection check)
Could you set up an event to fire on Form2 with the results of the db check? Subscribe to the event on Form1 and tell it to close if the conditions warrant.
Not sure if it would work or not, but something like:
public Form2 : Form
{
public delegate void DbCheckHandler(object sender, DbEventArgs e);
public event DbCheckHandler DbCheckComplete;
//check the db
DbCheckComplete(this, new DbEventArgs { ShouldClose = true; });
}
public Form1 : Form
{
Form2 form2 = new Form2();
form2.DbCheckComplete += new DbCheckHandler(CheckDbResult);
form2.Show();
private void CheckDbResult(object sender, DbEventArgs e)
{
if(e.ShouldClose)
{
this.Close();
}
}
}
With some help from previous answers posted by Hans Passant (here and here), My solution was as follows:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
new MyApp().Run(args);
}
class MyApp : WindowsFormsApplicationBase
{
protected override void OnCreateSplashScreen()
{
this.SplashScreen = new StartupSplash();
}
protected override void OnCreateMainForm()
{
Boolean result = false;
using (var connectiontest = new SqlConnection("myConnectionString"))
try
{
connectiontest.Open();
result = true;
}
catch (Exception ex)
{
result = false;
}
// pause not needed while checking for db connection as that takes its own amount of time to complete.
if (result)
{
System.Threading.Thread.Sleep(3000); //pause moved here to give the splash some time on screen if db connection available
this.MainForm = new MainWindow();
}
else
{
MessageBox.Show("Unable to connect to the database");
Environment.Exit(1); // shuts down the program if database connection not avaliable.
}
}
}
I am running server/client communication.
Now i want to write something on the server textBox and show it on the client textBox so I am sending a message from the server to the client which takes it using a static method:
static void Client_MessageReceived(object sender, MessageEventArgs e)
{
//Client only accepts text messages
var message = e.Message as ScsTextMessage;
if (message == null)
{
return;
}
}
Now I just want to append the message to the client textBox from this static method. I guess that I will need some kind of invoke but I don't know how to do it, and I cant find anything useful on Google.
Invoke method
public void AppendText(string what, bool debug = false)
{
if (debug)
return;
if (this.InvokeRequired)
{
this.Invoke(
new MethodInvoker(
delegate() { AppendText(what); }));
}
else
{
DateTime timestamp = DateTime.Now;
tbox.AppendText(timestamp.ToLongTimeString() + "\t" + what + Environment.NewLine);
}
}
Message received method
private void Client_MessageReceived(object sender, MessageEventArgs e)
{
//Client only accepts text messages
var message = e.Message as ScsTextMessage;
if (message == null)
{
return;
}
AppendText(message.Text, false);
//Console.WriteLine("Server sent a message: " + message.Text);
}
// Program.cs
public static ProgramForm Form;
publi static void Main()
{
// ...
Application.Run(Form = new ProgramForm());
// ...
}
public static void ChangeText(String message)
{
Form.TextBox1.Text = message;
}
// ProgramForm.cs
private void Client_MessageReceived(object sender, MessageEventArgs e)
{
if (e.Message != null)
Program.ChangeText(e.Message);
}
I created a windows service and installer that watches a collection of files for changes and copies any file that changes to a destination directory specified in the WatchlistConfig.xml file.
I have a couple issues with the service:
1. It has stopped running on one occasion. (unacceptable)
2. We sometimes have to attempt to start the service several times before it "takes".
I believe issue #1 is probably due to not handling fatal errors in the application. I found a bit of code that I tried to incorporate into the Main() method, but is written for a console app (Application is not a recognized class) and thus is commented out for now. Any idea which is the right class for implementing this in a service?
Issue #2 is most likely a timeout I'm guessing. The watchlist is currently comprised of 9 different files on different machines on the network. Connecting to these sources is not immediate (not all on a single domain). Is there a way to set a different timeout value for service startup?
Here's the relevant code. Additional classes on request.
Thanks in advance.
Edit: mistakenly posted the Main() from the test harness (console) which I use to debug. I've left it in place and add the Program class from the WinSvc Project
//Console Test harness
class Program
{
[STAThread]
static void Main(string[] args)
{
//AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
//Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
//Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
//Application.EnableVisualStyles();
//Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1());
TimedWatchList twl = new TimedWatchList(new PSU_Config(Helpers.GetConfigFile()));
Console.WriteLine("Press \'q\' to quit the sample.");
while (Console.Read() != 'q') ;
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
HandleException((Exception)e.ExceptionObject);
}
static void HandleException(Exception e)
{
//Handle/Log Exception Here
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
Logger.Loggit(e.Exception.Message);
}
}
//Actual Service
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Psu()
};
ServiceBase.Run(ServicesToRun);
}
}
public partial class Psu : ServiceBase
{
public Psu()
{
InitializeComponent();
TimedWatchList twl = new TimedWatchList(new PSU_Config(Helpers.GetConfigFile()));
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
}
public class TimedWatchList
{
public static PSU_Config Config { get; set; }
List<WatchFile> WatchList = new List<WatchFile>();
public TimedWatchList(PSU_Config config)
{
Config = config;
if (Config.PrintDebugMsgs) Logger.Loggit("Attempting to create TimedWatchList object");
WatchList = WatchListFactory.GetWatchList(Helpers.GetWatchListFile());
if (Config.PrintDebugMsgs) Logger.Loggit("TimedWatchList created");
Timer _timer = new Timer();
_timer.Interval += Config.Interval;
_timer.Enabled = true;
// register OnTimedEvent() to fire on each "tick"
_timer.Elapsed += OnTimedEvent;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
foreach (WatchFile file in WatchList)
{
file.PostOnUpdate();
}
}
}//TimedWatchList class
internal class WatchFile
// represents a file that is being watched
{
#region Props
public FileInfo SourceFile { get; set; }
public DirectoryInfo TargetPath { get; set; }
#endregion //Props
#region CTOR
public WatchFile() { }
public WatchFile(string fileName, string sourcePath, string destPath)
{
SourceFile = new FileInfo(Path.Combine(sourcePath, fileName));
TargetPath = new DirectoryInfo(destPath);
}
public WatchFile(FileInfo sourceFile, DirectoryInfo targetDirectory)
{
SourceFile = sourceFile;
TargetPath = targetDirectory;
}
#endregion //CTOR
public void PostOnUpdate()
{
//if (TimedWatchList.Config.PrintDebugMsgs) Logger.Loggit("WatchFile Post Event called for: " + SourceFile.Name);
//if (TimedWatchList.Config.PrintDebugMsgs) Logger.Loggit("Stored LastModified datetime: " + LastModified);
string targetPath = String.Format(#"{0}\{1}", TargetPath.FullName, SourceFile.Name);
{
try
{
//ensure directory exists
if (!Directory.Exists(TargetPath.FullName)) Directory.CreateDirectory(TargetPath.FullName);
//ensure file version is current
if (!File.Exists(targetPath) || (File.GetLastWriteTime(targetPath) != File.GetLastWriteTime(SourceFile.FullName)))
{
Logger.Loggit(String.Empty);
Logger.Loggit("Attempting to copy: " + SourceFile + " (" + File.GetLastWriteTime(SourceFile.FullName) + ")");
SourceFile.CopyTo(targetPath, true);
Logger.Loggit("\tCopy posted.\tLastModified: " + File.GetLastWriteTime(targetPath));
}
}
catch (IOException ioex)
{
Logger.Loggit("Error: " + ioex.Message);
}
catch (Exception ex)
{
Logger.Loggit("Error: " + ex.Message);
}
}
}
}// WatchFile class
There's really no need to guess; as a service you should be logging your errors to the system event log. Set a top level handler (as you've done), but don't expect to be able to handle it.
If the error was unhandled you're not going to be able to do anything about it there. Log it and exit. Catch the errors you can handle as soon as possible, test and design your code to not break otherwise.
You can set your service to restart automatically after a crash, but that should be a last resort. Bust out your debugger and figure out exactly where the errors are occurring and why. I see a lot of "it's probably [something]" and "it may be [something else]" statements here. Again, there is no good reason to guess; you have tools at your disposal which will help you figure out exactly what is going on.
You might want to simply wrap your function in a try / catch block to see what you might find.
try
{
MainAppFunctionality();
}
catch (Exception e)
{
//Not sure what you are going to do here, it's probably too late
}
I suggest you log to the Windows Event Log at various points in your application as a start so you can start to narrow down the location of the error.
I'm also not sure why you are using Console.Read() from a Windows Service context. As of Vista, there isn't a way for the service to interact with the desktop.