I must be doing something completely wrong but I cannot figure it out. I have a form and I add in VS a timer control. I also have a class that is watching for an application to start (notepad.exe). When the event arrives it is supposed to enable the timer, set the interval and on each tick do something (like firing a messagebox or changing a label). This seems not to be happening. A look in the code make help someone give me a clue. The code is below:
public partial class Monitor : Form
{
EventWatcher eventWatch = new EventWatcher();
ManagementEventWatcher startWatcher = new ManagementEventWatcher();
ManagementEventWatcher endWatcher = new ManagementEventWatcher();
public Monitor()
{
InitializeComponent();
startWatcher = eventWatch.WatchForProcessStart("notepad.exe");
endWatcher = eventWatch.WatchForProcessEnd("notepad.exe");
}
private void appTimer_Tick(object sender, EventArgs e)
{
label1.Text = "tick";
MessageBox.Show("Tick");
}
}
And the watcher class is
class EventWatcher
{
public ManagementEventWatcher WatchForProcessStart(string processName)
{
string queryString =
"SELECT TargetInstance" +
" FROM __InstanceCreationEvent " +
"WITHIN 2 " +
" WHERE TargetInstance ISA 'Win32_Process' " +
" AND TargetInstance.Name = '" + processName + "'";
// The dot in the scope means use the current machine
string scope = #"\\.\root\CIMV2";
// Create a watcher and listen for events
ManagementEventWatcher watcher = new ManagementEventWatcher(scope, queryString);
watcher.EventArrived += ProcessStarted;
watcher.Start();
return watcher;
}
public void ProcessStarted(object sender, EventArrivedEventArgs e)
{
Monitor monitor = new Monitor();
//set timer interval and start time for Monitor class. (form)
monitor.appTimer.Interval = 5000;
monitor.appTimer.Enabled = true;
MessageBox.Show("notepad started");
}
}
I noticed two things:
When notepad.exe starts and I have the MessageBox.Show("notpad started"); line commented out the messabox in the timer tick event won't fire. If it is as displayed above it will show me both messageboxes (notepad started and tick). However, the label1.Text will not change no matter what.
I am not sure what I am doing wrong. I am sure it has something to do with how the timer event is handled but I am not sure what I should be doing. Any ideas?
Your code creates a new instance of Monitor.
Thus you are not accessing the properties of the Monitor's instance you called eventWatch.WaitForProcessStart() in, so they're not changing.
One way to solve this would be an event that is fired as soon as ProcessStarted() is fired.
Your code could look like this:
class EventWatcher
{
public event EventHandler<EventArrivedEventArgs> ProcessStarted;
public ManagementEventWatcher WatchForProcessStart(string processName)
{
string queryString =
"SELECT TargetInstance" +
" FROM __InstanceCreationEvent " +
"WITHIN 2 " +
" WHERE TargetInstance ISA 'Win32_Process' " +
" AND TargetInstance.Name = '" + processName + "'";
// The dot in the scope means use the current machine
string scope = #"\\.\root\CIMV2";
// Create a watcher and listen for events
ManagementEventWatcher watcher = new ManagementEventWatcher(scope, queryString);
watcher.EventArrived += OnProcessStarted;
watcher.Start();
return watcher;
}
protected virtual void OnProcessStarted(object sender, EventArrivedEventArgs e)
{
EventHandler<EventArrivedEventArgs> copy = ProcessStarted;
if (copy != null)
copy(sender, e); // fire the event
}
}
public partial class Monitor : Form
{
EventWatcher eventWatch = new EventWatcher();
ManagementEventWatcher startWatcher = new ManagementEventWatcher();
ManagementEventWatcher endWatcher = new ManagementEventWatcher();
public Monitor()
{
InitializeComponent();
startWatcher = eventWatch.WatchForProcessStart("notepad.exe");
startWatcher.ProcessStarted += startWatcher_ProcessStarted; // subscribe to the event
endWatcher = eventWatch.WatchForProcessEnd("notepad.exe");
}
private void startWatcher_ProcessStarted(object sender, EventArrivedEventArgs e)
{
Monitor monitor = new Monitor();
//set timer interval and start time for Monitor class. (form)
monitor.appTimer.Interval = 5000;
monitor.appTimer.Enabled = true;
MessageBox.Show("notepad started");
}
private void appTimer_Tick(object sender, EventArgs e)
{
label1.Text = "tick";
MessageBox.Show("Tick");
}
}
It also looks like label1.Text will not change as you are running from a different thread. You would need to run an invoke on that label to update it from ManagementEventWatcher.
Use this class:
using System;
using System.Windows.Forms;
public static class ControlExtensions
{
/// <summary>
/// Executes the Action asynchronously on the UI thread, does not block execution on the calling thread.
/// </summary>
/// <param name="control"></param>
/// <param name="code"></param>
public static void UIThread(this Control #this, Action code)
{
if (#this.InvokeRequired)
{
#this.BeginInvoke(code);
}
else
{
code.Invoke();
}
}
}
and replace `label1.Text = "tick" ` with
this.UIThread(() => this.label1.Text = "tick"));
Related
I am in need of a solution to trigger code when an external application is closing / closes.
I am unable to use System.Diagnostics Process.GetProcessByName to detect if the process is running since it might conflict with an anticheat system. I would need trigger the snippet of code only when the program closes and only then.
I made a good, event-based implementation.
class Monitor
{
public event EventHandler ProgramStarted;
public event EventHandler ProgramClosed;
public Monitor(string process)
{
string pol = "2";
if (!process.EndsWith(".exe")) process += ".exe";
var queryString =
"SELECT *" +
" FROM __InstanceOperationEvent " +
"WITHIN " + pol +
" WHERE TargetInstance ISA 'Win32_Process' " +
" AND TargetInstance.Name = '" + process + "'";
var s = #"\\.\root\CIMV2";
ManagementEventWatcher watcher = new ManagementEventWatcher(s, queryString);
watcher.EventArrived += new EventArrivedEventHandler(OnEventArrived);
watcher.Start();
}
private void OnEventArrived(object sender, EventArrivedEventArgs e)
{
if (e.NewEvent.ClassPath.ClassName.Contains("InstanceDeletionEvent"))
{
EventHandler handler = ProgramClosed;
handler?.Invoke(this, e);
}
else if (e.NewEvent.ClassPath.ClassName.Contains("InstanceCreationEvent"))
{
EventHandler handler = ProgramStarted;
handler?.Invoke(this, e);
}
}
}
To use it, you just create an instance of the class and set up the events. For example:
static void Main(string[] args)
{
var mon = new Monitor("chrome");
mon.ProgramClosed += Mon_ProgramClosed;
mon.ProgramStarted += Mon_ProgramStarted;
Console.ReadKey(true);
}
private static void Mon_ProgramStarted(object sender, EventArgs e)
{
MessageBox.Show("Program started.");
}
private static void Mon_ProgramClosed(object sender, EventArgs e)
{
MessageBox.Show("Program closed.");
}
Make sure to add reference to System.Drawing if you're using a console app, and ,for winforms, adjust the modifiers.
Looking into possibility of making an USB distributed application
that will autostart on insertion of an USB stick and shutdown when removing the stick
Will use .Net and C#.
Looking for suggestion how to approach this using C#?
Update: Two possible solutions implementing this as a service.
- override WndProc
or
- using WMI query with ManagementEventWatcher
You can use WMI, it is easy and it works a lot better than WndProc solution with services.
Here is a simple example:
using System.Management;
ManagementEventWatcher watcher = new ManagementEventWatcher();
WqlEventQuery query = new WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2");
watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
watcher.Query = query;
watcher.Start();
watcher.WaitForNextEvent();
This works well for me, plus you can find out more information about the device.
using System.Management;
private void DeviceInsertedEvent(object sender, EventArrivedEventArgs e)
{
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
foreach (var property in instance.Properties)
{
Console.WriteLine(property.Name + " = " + property.Value);
}
}
private void DeviceRemovedEvent(object sender, EventArrivedEventArgs e)
{
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
foreach (var property in instance.Properties)
{
Console.WriteLine(property.Name + " = " + property.Value);
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
WqlEventQuery insertQuery = new WqlEventQuery("SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'");
ManagementEventWatcher insertWatcher = new ManagementEventWatcher(insertQuery);
insertWatcher.EventArrived += new EventArrivedEventHandler(DeviceInsertedEvent);
insertWatcher.Start();
WqlEventQuery removeQuery = new WqlEventQuery("SELECT * FROM __InstanceDeletionEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'");
ManagementEventWatcher removeWatcher = new ManagementEventWatcher(removeQuery);
removeWatcher.EventArrived += new EventArrivedEventHandler(DeviceRemovedEvent);
removeWatcher.Start();
// Do something while waiting for events
System.Threading.Thread.Sleep(20000000);
}
Adding to VitalyB's post.
To raise an event where ANY USB device is inserted, use the following:
var watcher = new ManagementEventWatcher();
var query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
watcher.Query = query;
watcher.Start();
This will raise an event whenever a USB device is plugged. It even works with a National Instruments DAQ that I'm trying to auto-detect.
VitalyB's answer does't cover remove of the device. I changed it a bit to trigger the event both when media is inserted and removed and also code to get the drive letter of the inserted media.
using System;
using System.Management;
namespace MonitorDrives
{
class Program
{
public enum EventType
{
Inserted = 2,
Removed = 3
}
static void Main(string[] args)
{
ManagementEventWatcher watcher = new ManagementEventWatcher();
WqlEventQuery query = new WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2 or EventType = 3");
watcher.EventArrived += (s, e) =>
{
string driveName = e.NewEvent.Properties["DriveName"].Value.ToString();
EventType eventType = (EventType)(Convert.ToInt16(e.NewEvent.Properties["EventType"].Value));
string eventName = Enum.GetName(typeof(EventType), eventType);
Console.WriteLine("{0}: {1} {2}", DateTime.Now, driveName, eventName);
};
watcher.Query = query;
watcher.Start();
Console.ReadKey();
}
}
}
A little bit edit on all above answer:
using System.Management;
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
bgwDriveDetector.DoWork += bgwDriveDetector_DoWork;
bgwDriveDetector.RunWorkerAsync();
}
private void DeviceInsertedEvent(object sender, EventArrivedEventArgs e)
{
string driveName = e.NewEvent.Properties["DriveName"].Value.ToString();
MessageBox.Show(driveName + " inserted");
}
private void DeviceRemovedEvent(object sender, EventArrivedEventArgs e)
{
string driveName = e.NewEvent.Properties["DriveName"].Value.ToString();
MessageBox.Show(driveName + " removed");
}
void bgwDriveDetector_DoWork(object sender, DoWorkEventArgs e)
{
var insertQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
var insertWatcher = new ManagementEventWatcher(insertQuery);
insertWatcher.EventArrived += DeviceInsertedEvent;
insertWatcher.Start();
var removeQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
var removeWatcher = new ManagementEventWatcher(removeQuery);
removeWatcher.EventArrived += DeviceRemovedEvent;
removeWatcher.Start();
}
}
You can also use WMI to detect insertion events. It's a little bit more complicated than monitoring for WM_CHANGEDEVICE messages, but it does not require a window handle which may be useful if you are running in the background as a service.
Try WM_CHANGEDEVICE handling.
My complete answer can be found here as a gist
I found the answer to determining the drive letter from the serial # from this question/answer
How to get the drive letter of USB device using WMI
And I modified Phil Minor's code to make it reactive:
public class UsbDetector : IUsbDetector
{
private const string Query = "SELECT * FROM {0} WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'";
private const string CreationEvent = "__InstanceCreationEvent";
private const string DeletionEvent = "__InstanceDeletionEvent";
private const int ReplayNumber = 1;
private readonly Subject<USBDeviceInfo> adds = new Subject<USBDeviceInfo>();
private readonly Subject<USBDeviceInfo> removes = new Subject<USBDeviceInfo>();
public UsbDetector()
{
var bgwDriveDetector = new BackgroundWorker();
bgwDriveDetector.DoWork += DoWork;
bgwDriveDetector.RunWorkerAsync();
}
public IObservable<USBDeviceInfo> Adds => adds.AsObservable();
public IObservable<USBDeviceInfo> Removes => removes.AsObservable();
private void DoWork(object sender, DoWorkEventArgs e)
{
SubscribeToEvent(CreationEvent, adds);
SubscribeToEvent(DeletionEvent, removes);
}
private static void SubscribeToEvent(string eventType, IObserver<USBDeviceInfo> observer)
{
WqlEventQuery wqlEventQuery = new WqlEventQuery(string.Format(Query, eventType));
ManagementEventWatcher insertWatcher = new ManagementEventWatcher(wqlEventQuery);
var observable = Observable.FromEventPattern<EventArrivedEventHandler, EventArrivedEventArgs>(
h => insertWatcher.EventArrived += h,
h => insertWatcher.EventArrived -= h).Replay(ReplayNumber);
observable.Connect();
observable.Select(a => a.EventArgs).Select(MapEventArgs).Subscribe(observer);
insertWatcher.Start();
}
private static USBDeviceInfo MapEventArgs(EventArrivedEventArgs e)
{
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
string deviceId = (string)instance.GetPropertyValue("DeviceID");
string serialNr = deviceId.Substring(deviceId.LastIndexOf('\\')).Replace("\\", "");
char driveLetter = GetDriveLetter(serialNr).First();
return new USBDeviceInfo(deviceId, serialNr, driveLetter);
}
Here is what we did with C# .Net 4.0 under a WPF app. We are still searching for an answer to "how to tell WHICH device type was inserted/removed", but this is a start:
using System.Windows.Interop;
...
public partial class MainWindow : Window
{
...
public MainWindow()
{
...
}
//============================================================
// WINDOWS MESSAGE HANDLERS
//
private const int WM_DEVICECHANGE = 0x0219; // int = 537
private const int DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 0x00000004;
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_DEVICECHANGE)
{
ReadDongleHeader();
}
return IntPtr.Zero;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Management;
using System.ComponentModel;
namespace ConsoleApplication4
{
public class usbState
{
public usbState()
{
}
private void DeviceInsertedEvent(object sender, EventArrivedEventArgs e)
{
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
foreach (var property in instance.Properties)
{
Console.WriteLine(property.Name + " = " + property.Value);
}
}
private void DeviceRemovedEvent(object sender, EventArrivedEventArgs e)
{
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
foreach (var property in instance.Properties)
{
Console.WriteLine(property.Name + " = " + property.Value);
}
}
public void bgwDriveDetector_DoWork(object sender, DoWorkEventArgs e)
{
WqlEventQuery insertQuery = new WqlEventQuery("SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'");
ManagementEventWatcher insertWatcher = new ManagementEventWatcher(insertQuery);
insertWatcher.EventArrived += new EventArrivedEventHandler(DeviceInsertedEvent);
insertWatcher.Start();
WqlEventQuery removeQuery = new WqlEventQuery("SELECT * FROM __InstanceDeletionEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'");
ManagementEventWatcher removeWatcher = new ManagementEventWatcher(removeQuery);
removeWatcher.EventArrived += new EventArrivedEventHandler(DeviceRemovedEvent);
removeWatcher.Start();
}
}
class Class1
{
private static void Main(string[] args)
{
usbState usb= new usbState();
BackgroundWorker bgwDriveDetector = new BackgroundWorker();
bgwDriveDetector.DoWork += usb.bgwDriveDetector_DoWork;
bgwDriveDetector.RunWorkerAsync();
bgwDriveDetector.WorkerReportsProgress = true;
bgwDriveDetector.WorkerSupportsCancellation = true;
// System.Threading.Thread.Sleep(100000);
Console.ReadKey();
}
}
}
I was hoping someone could point me in the right direction. I want to make a simple WPF application that has a button and a textbox. I click the button, and it starts to loop downloading a bunch of files. I can't seem to figure out how to not let the downloading stop the UI from updating. From what I can gather I'm probably going to have to use some threading code; but so far all the examples I've found and tried don't work for me. Any help or direction on where I should look and learn would be great. I can't seem to figure out how I can output those textbox.text messages around each file download.
foreach (var ticker in tickers)
{
var url = string.Format(urlPrototype, ticker, startMonth, startDay, startYear, finishMonth, finishDay, finishYear, "d");
var csvfile = directory + "\\" + ticker.ToUpper() + ".csv";
tbOutput.Text += "Starting Download of : " + ticker + "\n";
webClient.DownloadFile(url, csvfile);
tbOutput.Text += "End Download of : " + ticker + "\n";
numStocks++;
}
tbOutput.Text += "Total stocks downloaded = " + numStocks + "\n";
If you mark your method as async, you can use the DownloadFileTaskAsync method
await webClient.DownloadFileTaskAsync(url, csvfile)
If you choose to use the BackgroundWorker, it allows you to output those messages into the TextBox around each file download. Here is a crude example adapted for your requirement.
1) At the class level, create an instance of the BackgroundWorker class and add event handlers to the BackgroundWorker instance's events:
BackgroundWorker workerDownload = new BackgroundWorker();
workerDownload.WorkerReportsProgress = true;
workerDownload.DoWork += workerDownload_DoWork;
workerDownload.ProgressChanged += workerDownload_ProgressChanged;
workerDownload.RunWorkerCompleted += workerDownload_RunWorkerCompleted;
2) Create an event handler for the background worker's DoWork event:
The DoWork event handler is where you run the time-consuming operation
on the background thread. Any values that are passed to the background
operation are passed in the Argument property of the DoWorkEventArgs
object that is passed to the event handler.
private void workerDownload_DoWork(object sender, DoWorkEventArgs e)
{
foreach (var ticker in tickers)
{
// you can pass the required info as argument:
string[] arrArg = (string[])e.Argument;
string theUrl = arrArg[0];
string directory = arrArg[1];
var url = string.Format(theUrl, ticker);
var csvfile = directory + "\\" + ticker.ToUpper() + ".csv";
// perform the download operation and report progress:
workerDownload.ReportProgress(0, "Starting Download of : " + ticker + "\n");
webClient.DownloadFile(url, csvfile);
workerDownload.ReportProgress(100, "End Download of : " + ticker + "\n");
numStocks++;
}
}
3) Create an event handler for the background worker's ProgressChanged event:
In the ProgressChanged event handler, add code to indicate the
progress, such as updating the user interface.
private void workerDownload_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
tbOutput.Text += e.UserState.ToString();
}
4) Create an event handler for the RunWorkerCompleted event:
The RunWorkerCompleted event is raised when the background worker has
completed.
private void workerDownload_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
tbOutput.Text += "Total stocks downloaded = " + numStocks + "\n";
}
5) Start running the background operation by calling the RunWorkerAsync method:
int numStocks = 0;
string strDirectory = "<a_directory>";
string strUrl = string.Format(urlPrototype, startMonth, startDay, startYear, finishMonth, finishDay, finishYear, "d");
string[] args = new string[2] { strUrl, strDirectory };
workerDownload.RunWorkerAsync(args);
There are a lot ways to implement it. For example:
1) Using async/await if you programming in .Net Framework 4.5. It is simpler than BackgroundWorker
https://msdn.microsoft.com/en-us/library/hh191443.aspx
private async void button_Click(object sender, RoutedEventArgs e)
{
Uri someUrl=new Uri(#"http://dotnetperls.com");
WebClient webClient=new WebClient();
await webClient.DownloadFileTaskAsync(someUrl, csvFile);
}
2) BackgroundWorker. This class is really intended to make asynchronous operations to avoid freezing UI.
See http://www.wpf-tutorial.com/misc/multi-threading-with-the-backgroundworker
public partial class MainWindow : Window
{
BackgroundWorker bw;
public MainWindow()
{
InitializeComponent();
bw = new BackgroundWorker();
bw.DoWork += bw_DoWok;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
}
}
void bw_RunWorkerComleted(object sender, RunWorkerCompletedEventAgs e)
{
MessageBox.Show("The result is " + e.Result.ToString());
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
foreach (var ticker in tickers)
{
var url = string.Format(urlPrototype, ticker, startMonth, startDay, startYear, finishMonth, finishDay, finishYear, "d");
var csvfile = directory + "\\" + ticker.ToUpper() + ".csv";
webClient.DownloadFile(url, csvfile);
numStocks++;
}
e.Result = "End Of Download ";
}
private void button_Click(object sender, RoutedEventArgs e)
{
bw.RunWorkerAsync();
tbOutput.Text += "Starting Download of : " + ticker + "\n";
}
3) Use Thread class and update using Dispatcher class:
ThreadStart job = new ThreadStart(() =>
{
foreach (var ticker in tickers)
{
var url = string.Format(urlPrototype, ticker, startMonth, startDay, startYear, finishMonth, finishDay, finishYear, "d");
var csvfile = directory + "\\" + ticker.ToUpper() + ".csv";
webClient.DownloadFile(url, csvfile);
numStocks++;
}
Dispatcher.BeginInvoke((Action)(()=> tbOutput.Text += "End Download of : " + ticker + "\n";}));
});
Thread thread = new Thread(job);
thread.Start();
http://www.beingdeveloper.com/use-dispatcher-in-wpf-to-build-responsive-applications
I've googled this problem for the past week, it's killing my peace! Please help... EventArrivedEventHandler is stuck in a loop, and if I stop it, then it won't catch events. But when I use a handler method, the thread is still concentrating on the loop, and won't give attention to the new form I'm trying to make in the handler! Strange thing is, if I just use something small, like a MessageBox, it doesn't cause an issue, just trying to instantiate a form causes the buttons to NOT draw. Then shortly after the program stops responding. In case you're wondering where the form code is, it's just a standard form made by .NET, that works everywhere else in the code except for in the event handler.
Thanks!
class MainClass
{
public static void Main()
{
TaskIcon taskbarIcon;
EventWatch myWatcher;
taskbarIcon = new TaskIcon();
taskbarIcon.Show();
myWatcher = new EventWatch();
myWatcher.Start();
Application.Run();
}
}
public class TaskIcon
{
public void Show()
{
NotifyIcon notifyIcon1 = new NotifyIcon();
ContextMenu contextMenu1 = new ContextMenu();
MenuItem menuItem1 = new MenuItem();
MenuItem menuItem2 = new MenuItem();
contextMenu1.MenuItems.AddRange(new MenuItem[] { menuItem1, menuItem2 });
menuItem1.Index = 0;
menuItem1.Text = "Settings";
menuItem1.Click += new EventHandler(notifyIconClickSettings);
menuItem2.Index = 1;
menuItem2.Text = "Exit";
menuItem2.Click += new EventHandler(notifyIconClickExit);
notifyIcon1.Icon = new Icon("app.ico");
notifyIcon1.Text = "Print Andy";
notifyIcon1.ContextMenu = contextMenu1;
notifyIcon1.Visible = true;
}
private static void notifyIconClickSettings(object Sender, EventArgs e)
{
MessageBox.Show("Settings Here");
}
private static void notifyIconClickExit(object Sender, EventArgs e)
{
//taskbarIcon.Visible = false; // BONUS QUESTION: Why can't I hide the tray icon before exiting?
Application.Exit();
}
}
public class EventWatch
{
public void Start()
{
string thisUser = WindowsIdentity.GetCurrent().Name.Split('\\')[1];
WqlEventQuery query = new WqlEventQuery();
query.EventClassName = "__InstanceCreationEvent";
query.Condition = #"TargetInstance ISA 'Win32_PrintJob'";
query.WithinInterval = new TimeSpan(0, 0, 0, 0, 1);
ManagementScope scope = new ManagementScope("root\\CIMV2");
scope.Options.EnablePrivileges = true;
ManagementEventWatcher watcher = new ManagementEventWatcher(scope, query);
watcher.EventArrived += new EventArrivedEventHandler(showPrintingForm);
watcher.Start();
}
void showPrintingForm(object sender, EventArrivedEventArgs e)
{
// MessageBox.Show("This will draw just fine");
Form1 myForm;
myForm = new Form1();
myForm.Show(); // This causes a hangup
}
}
My guess would be that the ManagementEventWatcher calls the EventArrived handler from a different thread than the UI thread. Then your showPrintingForm is executed on that thread and accessing UI from a different thread than the UI thread is bad. You need to marshal your code back onto the UI thread.
this is my first C# post.
I have a question on event binding.
I have a FileWatcher which I'd like to bind to functions that are defined in a separate class called FileWatcherEvents.
I don't want the events to be declared in the Program class, how can this be done?
As you can see, I try to bind the events for Created and Deleted.
The problem is that these events are not called when I delete or create a file in the folder. But when I declare the event handlers in the Program class, it does work.
Any help or insights is appreciated.
Program
using System.IO;
class Program : ServiceBase
{
private FileSystemWatcher _watcher;
public Program()
{
FileWatcherEvents fwe = new FileWatcherEvents();
this._watcher = new FileSystemWatcher();
((System.ComponentModel.ISupportInitialize)(this._watcher)).BeginInit();
//
// _watcher
//
this._watcher.EnableRaisingEvents = true;
this._watcher.Filter = "*.txt";
this._watcher.NotifyFilter =
((NotifyFilters)(((((NotifyFilters.FileName
| NotifyFilters.DirectoryName)
| NotifyFilters.LastWrite)
| NotifyFilters.LastAccess)
| NotifyFilters.CreationTime)));
this._watcher.Path = "T:\\out\\";
this._watcher.Deleted += new FileSystemEventHandler(fwe.ShipmentFileCreated);
this._watcher.Created += new FileSystemEventHandler(fwe.FileDeleted);
((System.ComponentModel.ISupportInitialize)(this._watcher)).EndInit();
}
static void Main(string[] args)
{
Program prg = new Program();
Console.Write(FileManager.getNewestFile("T:\\out\\"));
while (Console.Read() != 'q') ;
}
}
FileWatcherEvents
class FileWatcherEvents
{
public void ShipmentFileCreated(object sender, FileSystemEventArgs e)
{
Console.WriteLine("CREATED: " + sender.ToString() + e.ToString());
}
public void FileDeleted(object sender, FileSystemEventArgs e)
{
Console.WriteLine("DELETED: " + sender.ToString() + e.ToString());
}
}
I believe you would need to declare fwe in a larger scope, like at the Program level instead of inside the Program constructor. Otherwise the object will go away, and possibly all the events that lead to it as well (never been entirely clear on what happens to the functions that handle events on an instance when the instance goes away, but the events could still occur, but it's very possible they will no longer run).
Edit:
I got your code to work with some minor adjustments. Mainly I had to move EnableRaisingEvents to the end of the block because .NET throws an exception if you do it before setting the path. How did you not see that exception?
class Program
{
private FileSystemWatcher _watcher;
public Program()
{
FileWatcherEvents fwe = new FileWatcherEvents();
this._watcher = new System.IO.FileSystemWatcher();
this._watcher.Filter = "*.txt";
this._watcher.NotifyFilter = ((System.IO.NotifyFilters)(((((
System.IO.NotifyFilters.FileName | System.IO.NotifyFilters.DirectoryName)
| System.IO.NotifyFilters.LastWrite) | System.IO.NotifyFilters.LastAccess)
| System.IO.NotifyFilters.CreationTime)));
this._watcher.Path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
this._watcher.Deleted += new System.IO.FileSystemEventHandler(fwe.ShipmentFileCreated);
this._watcher.Created += new System.IO.FileSystemEventHandler(fwe.FileDeleted);
this._watcher.EnableRaisingEvents = true;
Console.ReadLine();
}
public static void Main()
{
Program prg = new Program();
using (System.IO.StreamWriter w = new System.IO.StreamWriter(
System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "TestFile.txt"), false))
{
w.WriteLine(DateTime.Now.ToLongTimeString());
}
Console.ReadLine();
}
}
class FileWatcherEvents
{
public void ShipmentFileCreated(object sender, FileSystemEventArgs e)
{
Console.WriteLine("CREATED: " + sender.ToString() + e.ToString());
}
public void FileDeleted(object sender, FileSystemEventArgs e)
{
Console.WriteLine("DELETED: " + sender.ToString() + e.ToString());
}
}
Turns out that the code works fine, the events fired, but the functions weren't because of the *.txt filter in the private FileSystemWatcher object.