I'm starting a process (namely gnuplot.exe) from within a C# application.
The process can open some window and for that process i'd like to intercept the events of:
opened window
closed window
focused window
The basic idea is to handle if the user closes some windows or changes the active window and so on, referring only to the started process. In other word, i don't want to handle others focus changes or closed windows events which are not thrown by a gnuplot window.
Can you help me? Is it possible to avoid polling? Which api should i refer to? Can you paste/link an mwe or some example code?
Thank you in advance
Update
As suggested by Eric Brown I tried this way, but still not works. Can you help me to detect where am I wrong?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Windows;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Windows.Automation;
namespace WinApiEvents
{
class Program
{
public static void Main()
{
Process gp = new Process();
gp.StartInfo.FileName = #"C:\Software\gp463-win32\gnuplot\bin\gnuplot.exe";
gp.StartInfo.UseShellExecute = false;
gp.StartInfo.RedirectStandardInput = true;
gp.StartInfo.CreateNoWindow = true;
gp.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
gp.Start();
AutomationElement targetElement =
AutomationElement.FromHandle(gp.Handle);
StructureChangedEventHandler structChangedHandler =
new StructureChangedEventHandler(OnGnuplotWindowStructureChanged);
Automation.AddStructureChangedEventHandler(
targetElement, TreeScope.Element, structChangedHandler);
AutomationEventHandler focusHandler =
new AutomationEventHandler(OnGnuplotWindowFocusGained);
Automation.AddAutomationEventHandler(
AutomationElement.AutomationFocusChangedEvent, targetElement, TreeScope.Element, focusHandler);
StringBuilder sb = new StringBuilder();
sb.AppendLine("set term wxt 1 enhanced");
sb.AppendLine("plot sin(x)");
gp.StandardInput.WriteLine(sb.ToString());
gp.StandardInput.Flush();
sb.Clear();
sb.AppendLine("set term wxt 2 enhanced");
sb.AppendLine("plot cos(x)");
gp.StandardInput.WriteLine(sb.ToString());
gp.StandardInput.Flush();
sb.Clear();
sb.AppendLine("set term wxt 3 enhanced");
sb.AppendLine("plot atan(x)");
gp.StandardInput.WriteLine(sb.ToString());
gp.StandardInput.Flush();
sb.Clear();
MessageBox.Show("Click to exit.");
}
private static void OnGnuplotWindowStructureChanged(object src, StructureChangedEventArgs e)
{
Console.WriteLine("structure changed window, id=" + e.EventId.ProgrammaticName);
}
private static void OnGnuplotWindowFocusGained(object src, AutomationEventArgs e)
{
Console.WriteLine("focused window, id=" + e.EventId.ProgrammaticName);
}
}
}
Thank you in advance
I would use the UI Automation framework for this.
I assume you have (or can get) the gnuplot window handle. Once you have that, you can get the UI Automation element for that window, and set up FocusChanged event handlers, and StructureChanged handlers to detect subwindow opening & closing. The WindowClosed event will tell you if the gnuplot window itself closes. (You can use this on subwindows as well, but you'll still need to listen for StructureChanged events to detect subwindow open events.)
Related
is it possible to read keyboard inputs without always having my console application focused?
I would like to do something with a button without always going to the console.
Doesn't that somehow work with events? Unfortunately I only found unsightly solutions with Forms.
This solution from #Siarhei Kuchuk didn't help me either:
Global keyboard capture in C# application
The OnKeyPressed event is activated but is not triggered.
Does somebody has any idea?
That's possible. You may google "keyloggers" and find many examples but I'm gonna give you a very rough bare boned one.
But first you have to add a refrence to System.Windows.Forms.dll for this to work
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
[DllImport("User32.dll")]
private static extern short GetAsyncKeyState(System.Int32 vKey);
static void Main(string[] args)
{
while (true)
{
Thread.Sleep(500);
for (int i = 0; i < 255; i++)
{
int state = GetAsyncKeyState(i);
if (state != 0)
{
string pressedKey= ((System.Windows.Forms.Keys)i).ToString();
switch (pressedKey)
{
default:
Console.WriteLine("You have pressed: " + pressedKey);
break;
}
}
}
}
}
}
}
I'm writing a simple watchdog application that will start and stop another application I'm writing based on whether the third application is running or not.
in other words, if application A is running then start application B. When application A stops, stop application B.
the problems is that my watchdog keeps stopping application B and immediately restarts it.
here is what I have:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;
using System.Windows.Forms;
using WindowScrape.Types;
namespace ConnectAndWait
{
class CheckForApplication
{
public static System.Windows.Forms.Timer _timer = new System.Windows.Forms.Timer();
public static bool goodtogo;
public static void checking()
{
_timer.Interval = 3000;
_timer.Tick += _timer_Tick;
_timer.Start();
}
public static void _timer_Tick(object sender, EventArgs e)
{
Process[] myprocess = Process.GetProcessesByName("ApplicationA");
Process[] proc = Process.GetProcessesByName("notepad");
if (myprocess.Length == 0)
{
goodtogo = false;
}
else
{
var win = Process.GetProcessesByName("ApplicationA");
var mainform = NativeMethods.FindWindow("TMainForm_ihm", null);
var children = NativeMethods.FindWindowEx(mainform, IntPtr.Zero, "TRzPageControl", null);
var final = NativeMethods.FindWindowEx(children, IntPtr.Zero, "TRzTabSheet", "Operation" );
if (final.ToString() != "0")
{
goodtogo = true;
}
else
{
goodtogo = false;
}
}
if (goodtogo == true)
{
if (proc.Length == 0)
{
Process.Start("notepad.exe");
MessageBox.Show("notepad started");
}
}
else if (goodtogo == false)
{
if (proc.Length != 0)
{
proc[0].Kill();
MessageBox.Show("process killed"); // <-- This never gets fired
// as long as application A keeps running. At first I thought I was stopping it
// with this code so I put the messageBox in to test that theory.
}
}
}
}
}
I am starting and stopping notepad for now just for testing.
can anyone see what I am doing wrong?
First: what is causing notepad to stop and then restart again even though the other application is still running?
Second: if there is anything else I should be doing differently please point that out as well.
As always, thank you so much for any help you can provide.
EDIT:
I didn't mention it before because of my lack of knowledge I didn't think it would be relevant.
The entire scope of the project is that I am writing an integration between two existing applications. If the one application is not running then there is no need for my application to use resources. So my thought was that a watchdog would take up fewer resources than the application itself.
My integration application uses multiple threads and gets and sets a lot of information between the other two applications.
The end user will start and stop application A whenever needed.
Application B is my integration application.
Application C - the one previously not mentioned - runs as a service and interacts with a database.
The watchdog application in question is simply to start and stop my integration application whenever Application A stops or starts.
There is simply no need for such a 'watchdog'. Use Job objects and bind the processes in a job. Read Destroying all child processes (and grandchildren) when the parent exits. See Working example of CreateJobObject/SetInformationJobObject pinvoke in .net? for C# examples.
For process start, use WMI Win32_ProcessStartTrace, see .NET Process Monitor.
I try to play jpg (in loop), after click mp4 should be played after end, that jpg should play again. I dont know why but after I play in axWindowsMediaPlayer1_PlayStateChange vido play and then stop. Help.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Video
{
public partial class Form1 : Form
{
bool clicked = false;
public Form1()
{
InitializeComponent();
axWindowsMediaPlayer1.URL = "wait2.JPG";
}
private void axWindowsMediaPlayer1_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if (axWindowsMediaPlayer1.playState == WMPLib.WMPPlayState.wmppsMediaEnded & clicked== true)
{
clicked = false;
axWindowsMediaPlayer1.settings.setMode("Loop", true);
axWindowsMediaPlayer1.URL = "wait2.JPG";
axWindowsMediaPlayer1.Ctlcontrols.play();
}
}
private void axWindowsMediaPlayer1_ClickEvent(object sender, AxWMPLib._WMPOCXEvents_ClickEvent e)
{
axWindowsMediaPlayer1.settings.setMode("Loop", false);
axWindowsMediaPlayer1.URL = "video.MP4";
axWindowsMediaPlayer1.Ctlcontrols.play();
clicked = true;
}
}
}
I wish someone had replied to this question the time it was posted. It took me a lot of time to figure out why I was not able to start a new video by setting the URL property. I finally found the answer to this issue here:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd562470%28v=vs.85%29.aspx
The problem is with setting the URL property from within the axWindowsMediaPlayer1_PlayStateChange() event handler. According to the above msdn document:
"Do not call this method from event handler code. Calling URL from an event handler may yield unexpected results."
So the URL property has to be set outside of the even handler. I also tried Dispatcher.Invoke() and even starting a new thread from within the event handler to set the URL property; but that too did not help. It really has to come from outside of the event handler!
Well,
I am not sure if someone already asked this qusiton before. I was trying to look arround but noting came up. (if there is, please show me and close this. I am very sorry!)
For a few days now I am looking for a way that when I click on a button in my windows form in C# it will copy paste something to somewhere else.
The best way to expline this:
Lets say I got a Ms Word open, and I want that when I will click on a button in my windows form, after 5 seconds, it will write something in my word office. Of course I will open the Ms Word by my self.
Another thing: is how to make your mouse click on hes key?
edit:
When i use this code --
int forhow = int.Parse(textBox1.Text);
for(int i = 0;i <forhow; i++)
{
i++;
SendKeys.Send("ספאמר על ידי פריזו - ספאמר על גירסא ראשונה");
//ספאמר על ידי פThread.Sleep(1200);
//Thread.Sleep(5000);
SendKeys.Send("{ENTER}");
}
well, its should do it only 1 time. is i write 1 in the text box. but, it is doing it about 50 times. and the stop. any one knows why? + . if you lick on the button, the program stops to work until she compltite all the "Send:".
I couldn't find a way to force a mouse click, but you cam mimic the keyboard using the SendKeys class. All code that is not in between "//{" and "//}" was generated by visual studio.
Hope this helps!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
//{
using System.Diagnostics;
//}
namespace ClickToWord
{
public partial class Form1 : Form
{
//{
Process imsWord = new Process();
Timer tempTime = new Timer();
int counter = 0;
//}
public Form1()
{
InitializeComponent();
//{
imsWord.StartInfo.FileName = #"";
//Inside the "" put the path to the file/application. No need to escape it, because of the "#"
tempTime.Interval = 1000;
//The interval in miliseconds
tempTime.Tick += new EventHandler(tempTime_Tick);
//}
}
void tempTime_Tick(object sender, EventArgs e)
{
//{
char send = 'a';
send += (char)(counter % 26);
SendKeys.Send(send.ToString());
counter++;
//An example of looping through the alphabet. Send any string via SendKeys, and it will act as if the keyboard ent it.
//This mimics keyboard strokes, and requires the document to have focus. That is why it is not the ideal way to do this.
//To programmatically communicate with Word, use the Microsoft Word Object Model library.
//tempTime.Enabled = false;
//}
}
private void button1_Click(object sender, EventArgs e)
{
//{
imsWord.Start();
//Starts the proccess
tempTime.Enabled = true;
//Starts the timer
//}
}
}
}
i am trying to make a basic IRC client...but my problem is getting the text to display in a RTF box without it lagging
i settled on using threading, and i want to update the RTF box in a thread, but i cant because it gives me errors about the RTF box element not being static?
any insight? i will paste code if you guys want it
ok here is the code (do edits bump?)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Net;
namespace IrcClient
{
public partial class mainWindow : Form
{
static IRC client;
static string newLine, oldLine;
public mainWindow()
{
InitializeComponent();
}
private void main()
{
}
private void mainWindow_Load(object sender, EventArgs e)
{
client = new IRC("irc.freenode.net" ,6667, "jimi__hendrix");
new Thread(new ThreadStart(update)).Start();
}
private static void update()
{
newLine = client.sr.ReadLine();
Thread.Sleep(50);
}
private void btnSend_Click(object sender, EventArgs e)
{
client.privmsg(inputBox.Text);
messageBox.AppendText(inputBox.Text + "\n");
inputBox.Text = "";
}
private void timer1_Tick(object sender, EventArgs e)
{
if (newLine != oldLine)
{
messageBox.AppendText(newLine + "\n");
oldLine = newLine;
}
}
}
class IRC
{
TcpClient connection;
NetworkStream stream;
public StreamWriter sw;
public StreamReader sr;
string nick;
public IRC(string server, int port, string Nick)
{
try
{
connection = new TcpClient(server, port);
stream = connection.GetStream();
sr = new StreamReader(stream);
sw = new StreamWriter(stream);
nick = Nick;
sw.WriteLine("PASS " + "caruso11");
sw.Flush();
sw.WriteLine("NICK " + nick);
sw.Flush();
sw.WriteLine("USER Jimi__Hendrix 8 irc.freenode.net :Jimi__Hendrix");
sw.Flush();
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
public void privmsg(string msg)
{
sw.WriteLine(msg);
sw.Flush();
}
public void parse(string msg)
{
}
}
}
some of the methods are blank and some code could be cleaned up, but i want to get this done first...also, theres the code generated by visual studios that sets up the window
In general, trying to update a Control from a thread other than the main thread will not work, due to limitations of Windows. If you need to call a method or set a property on the RTF box from your worker thread, you'll probably need to use Invoke or BeginInvoke. This might look like the following:
void MyThreadMethod()
{
// stuff
this.rtfBox.BeginInvoke( (MethodInvoker)(()=> this.rtfBox.Text = "foo") );
// stuff
}
Edit: As others point out, if this is actually failing to compile due to an error about the control not being static, you're probably trying to reference a member variable from a static function, which is illegal. Posting code will help narrow down the problem.
I believe you are using Windows Forms. Check out this text about it, there is some remarks that you have to take care before making a thread accessing forms elements directly.
If this is not exactly your problem, please elaborate more the question.
RULE: You should not access one window from another thread.
Use this technique:
from your thread raise an event to update the RTF (with required text etc data)
on the GUI thread use the following:
use the "InvokeRequired" property to verify call is from GUI thread or not
Use the Invoke method (you will need a delegate for this)
BeginInvoke also works but the only problem is it does not really guarantee immediate start (it uses threadpool). I prefer to use the Invoke method instead.
Others have already mentioned what the problem you are experienced is, and how to solve it.
Not that having a separate worker thread is a bad idea, it seems odd that you need multiple threads because of performance reasons. It seems that for as something as simple as an IRC client, you should be able to do everything on one thread without any UI sluggishness. Maybe you can post some code so that we can see what the root of the problem is?
The RichTextBox is on the UI thread so you're not going to be able to access the RichTextBox unless your on the UI thread. How are you loading the content? How big is the content? Is the lag coming from loading the content or the RTF box parsing it?
You're probably referencing a member variable of the form, instead of a static variable, thus the error.
Anyway this is quite a wrong approach, since UI elements can only be updated from the UI thread, otherwise you'll get a cross-thread operation exception. So you'll need to do Invoke() to the set-text method on the UI thread, which will eventually 'lag' too.
Not sure what you mean by 'lagging', you may try making your parent form double-buffered to reduce flicker.