I have a method that gets called into a new thread like so:
if (!_isPlaying)
{
_playBackThread = new Thread(PlayMacroEvents);
_playBackThread.Start();
...
}
The method looks like:
Process proc = Process.GetProcessesByName("notepad").FirstOrDefault();
if (proc != null)
{
SetForegroundWindow(proc.MainWindowHandle);
}
int loopCount = this.dsUserInput.Tables[0].Rows.Count;
for (int i = 0; i < loopCount; i++)
{
foreach(MacroEvent macroEvent in _events)
{
Thread.Sleep(macroEvent.TimeSinceLastEvent);
switch (macroEvent.MacroEventType)
{
...
The problem I'm having is that if notepad is not already up (not minimized) there is enough delay between setting the foreground window and the macro output that often the first series of commands is not shown. How can I put enough of a pause to make sure that the window is up before the the macros start kicking in? A Thread.Sleep() between SetForegroundWindow() and the for loop does not seem to do the trick. Ideas?
The reason the first series of inputs were being dropped is because I also had to include the command to ShowWindow like so..
in the class header:
private const int SW_RESTORE = 9;
[DllImport("user32")]
private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
...
In the macro thread method I changed
if (proc != null)
{
SetForegroundWindow(proc.MainWindowHandle);
}
to look like:
if (proc != null)
{
ShowWindow(proc.MainWindowHandle, SW_RESTORE);
SetForegroundWindow(proc.MainWindowHandle);
}
Use some api to get the active window, and wait until the window belonging to notepad is the active one
Related
I have a lookup program (.exe) that I want to launch that contains a textbox. I want to launch this program from my main form and copy paste data from my main form into the lookup program (.exe).
I've already wrote some code to do this and it works fine but I'm using Thread.Sleep() to wait until the program loads. I was thinking of something like WaitForInputIdle() but I'm not sure how that works.
private IntPtr handle;
private void launchProgram()
{
// Copy the text in the datafield to Clipboard
Clipboard.SetText(serialTextBox.Text, TextDataFormat.Text);
bool isRunning = Process.GetProcessesByName("Serial Search.exe").Any();
using (Process process = new Process())
{
if (!isRunning)
{
process.StartInfo.FileName = #"C:\Serial Search.exe";
process.Start();
// Give the process some time to startup - I want to remove this line and interact when fully loaded
Thread.Sleep(2000);
Process[] pname = Process.GetProcessesByName("Serial Search.exe");
if (pname.Length > 0)
{
handle = pname[0].MainWindowHandle;
SetForegroundWindow(handle);
}
var activatedHandle = GetForegroundWindow();
var vPprocess = Process.GetProcessesByName("Serial Search.exe");
while (GetActiveWindowTitle() == "Serial Search")
{
SendKeys.Send("^V");
SendKeys.Send("{ENTER}");
break;
}
}
else
{
Process[] pname = Process.GetProcessesByName("Serial Search.exe");
handle = pname[0].MainWindowHandle;
SetForegroundWindow(handle);
var activatedHandle = GetForegroundWindow();
var vPprocess = Process.GetProcessesByName("Serial Search.exe");
while (GetActiveWindowTitle() == "Serial Search")
{
SendKeys.Send("^A");
SendKeys.Send("^V");
SendKeys.Send("{ENTER}");
break;
}
}
}
}
}
I want to remove the Thread.Sleep part and just have the form instantaneously interact with the .exe whenever it's loaded. Any ideas how I could do this?
You could simplify the code down to:
private IntPtr handle;
private void launchProgram()
{
handle = IntPtr.Zero;
string fullPathFileName = #"C:\Serial Search.exe";
string friendlyFileName = System.IO.Path.GetFileNameWithoutExtension(fullPathFileName);
Process P = Process.GetProcessesByName(friendlyFileName).FirstOrDefault();
if (P != null)
{
handle = P.MainWindowHandle;
}
else
{
P = Process.Start(fullPathFileName);
P.WaitForInputIdle();
handle = P.MainWindowHandle;
}
if (!handle.Equals(IntPtr.Zero))
{
// Copy the text in the datafield to Clipboard
Clipboard.SetText(serialTextBox.Text, TextDataFormat.Text);
handle = pname[0].MainWindowHandle;
SetForegroundWindow(handle);
SendKeys.Send("^A");
SendKeys.Send("^V");
SendKeys.Send("{ENTER}");
}
}
Note that Process.GetProcessesByName() expects the "friendly" version of the filename without the ".exe" on the end:
The process name is a friendly name for the process, such as Outlook,
that does not include the .exe extension or the path.
Maybe take the messy route and check for color at a specific pixel which will indicate the program is loaded. Or maybe look for some CPU usage drop or hard drive usage drop of the process that can be associated with the program done loading
My problem is that I created a simple application where I have webrowser control. It navigates every 20 seconds to a new site. After some number of navigations memory occupied by the application increases. I tried to dispose, delete and create again the webrouser control, but couldn't succeed. The only way to release all resources of the application is reboot it. I spent lots of effort trying to solve this problem. Please, give me some hints or links where I can read about it. Thanks in advance.
The actual code is much bigger than the demonstrated one, but the idea is the same. Code looks like this:
for (int i = 0; i < 100000; i++)
{
webBrowser1.Navigate("http://stackoverflow.com");
Wait(20000);
}
Method definition:
private void Wait(long value)
{
Stopwatch sw = new Stopwatch();
sw.Start();
while (sw.ElapsedMilliseconds < value)
Application.DoEvents();
}
Problem is not actual now because the solution is found by using another browser control named WebKitBrowser. Thanks for all who tried to help me. It was my first question on this briliant site. I liked it very much.
The problem is still actual. I tried to use a method shown in below link but didn't succeed. How to Fix the Memory Leak in IE WebBrowser Control?
It decreases the memory for a while, then again increases significantly. And so circularly.
Here is the modified code:
public partial class Form1 : Form
{
[DllImport("KERNEL32.DLL", EntryPoint = "SetProcessWorkingSetSize", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
internal static extern bool SetProcessWorkingSetSize(IntPtr pProcess, int dwMinimumWorkingSetSize, int dwMaximumWorkingSetSize);
[DllImport("KERNEL32.DLL", EntryPoint = "GetCurrentProcess", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
internal static extern IntPtr GetCurrentProcess();
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 100000; i++)
{
webBrowser1.Navigate("http://stackoverflow.com");
while (webBrowser1.ReadyState != WebBrowserReadyState.Complete) Application.DoEvents();
// anytime when I want to reduce the occupied memory I do this
IntPtr pHandle = GetCurrentProcess();
SetProcessWorkingSetSize(pHandle, -1, -1);
}
}
}
You're blocking your main UI thread message loop and using Application.DoEvents, which is evil!
Instead of this, you can use a System.Windows.Forms.Timer like this:
class Form1 : Form
{
Timer _Timer;
int _Index = 0;
public Form1()
{
_Timer = new Timer { Enabled = true, Interval = 20000 };
_Timer.Tick += ( s, e ) => TimerTick();
}
void TimerTick()
{
if ( _Index >= 100000 )
{
_Timer.Dispose();
_Timer = null;
return;
}
webBrowser.Navigate( ... );
_Index++;
}
I'm guessing this will solve your problem. In any case, it's worth doing.
I solved the problem using WebKit Browser. Here is the link for those who are also interested in using it: http://webkitdotnet.sourceforge.net/basics.php?p=4
I'm creating an app that is threaded. I started GUI (Announce : Form) as separate thread.
That window will be very minimalistic with one input box and maybe a button. On another thread there will be Tcp Client running and when it gets info from TcpServer it should pass what it gets into that inputbox and show the gui (and topmost windows). After couple of seconds the gui should hide itself and wait for another tcp msg and so on.
public void setTextBox(string varText) {
if (InvokeRequired) {
textBox.BeginInvoke(new textBoxCallBack(setTextBox), new object[] {varText});
} else {
textBox.Text = varText;
}
}
This code is used to fill the textBox from the Tcp Thread. The only problem now is getting the window show and hide properly. Been trying many solutions and always something went wrong. Like:
private void windowStateChange(string varState) {
if (InvokeRequired) {
Invoke(new WindowStateChangeCallBack(windowStateChange), new object[] {varState});
} else {
if (varState == "Hide") {
//Hide();
// TopMost = false;
//TopMost = varState != FormWindowState.Minimized;
} else {
//Show();
//MessageBox.Show("TEST1");
}
}
}
public void windowStateChangeDiffrent(FormWindowState varState) {
if (InvokeRequired) {
Invoke(new WindowStateChangeCallBack(windowStateChange), new object[] {varState});
} else {
WindowState = varState;
// Hide();
TopMost = varState != FormWindowState.Minimized;
}
}
What would be best aproach to do this (and fastest, as time matters)?
Answer 1 which seems to work:
private static void windowStateChange(string varState) {
if (mainAnnounceWindow.InvokeRequired) {
mainAnnounceWindow.BeginInvoke(new StateCallBack(windowStateChange), new object[] {varState});
} else {
if (varState == "Hide") {
mainAnnounceWindow.Hide();
mainAnnounceWindow.TopMost = false;
} else {
mainAnnounceWindow.Show();
mainAnnounceWindow.TopMost = true;
}
}
}
Anything bad about it?
Making the form hide with form.Hide() should pose no problems.
However I've experienced making the form show again does not always work.
So if you're encountering the same problem, you could use something like this:
string RunningProcess = Process.GetCurrentProcess().ProcessName;
Process[] processes = Process.GetProcessesByName(RunningProcess);
int SW_SHOW = 5, SW_HIDE = 0, SW_RESTORE = 9, SW_SHOWNORMAL = 1;
for (int a = 0; a < processes.Length; a++)
{
IntPtr hWnd = processes[a].MainWindowHandle;
ShowWindowAsync(hWnd, SW_RESTORE);
ShowWindowAsync(hWnd, SW_SHOWNORMAL);
ShowWindowAsync(hWnd, SW_SHOW);
SetForegroundWindow((int)hWnd);
}
//Required Win32 API imports
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
static extern bool ShowWindowAsync(IntPtr windowHandle, int cmd);
[System.Runtime.InteropServices.DllImportAttribute("User32.dll")]
private static extern IntPtr SetForegroundWindow(int hWnd);
you might try
form.Hide();
but make sure that you show/hide the form from the same thread that created them
this.Invoke(new MethodInvoker(this.hide()));
Another approach would be to expose events on your TCP thread object. It could define an event such as RecievedData(...) then the GUI could subscribe to that event and update itself without having to do any InvokeRequired checks etc.
Update: link to C# events tutorial
http://msdn.microsoft.com/en-us/library/aa645739%28VS.71%29.aspx
Form.Hide() is the right method to hide the form. I remember having issues with Form.Show(), I have a vague memory of having to use Form.Activate() as well to get the form to restore correctly.
You're already dealing with thread marshalling correctly (InvokeRequired and Invoke). You could also use Form.BeginInvoke(), which is an async version of Form.Invoke. That might be faster.
I have this method:
private delegate void watcherReader(StreamReader sr);
private void watchProc(StreamReader sr) {
while (true) {
string line = sr.ReadLine();
while (line != null) {
if (stop) {
return;
}
//Console.WriteLine(line);
line = stripColors(line);
txtOut.Text += line + "\n";
line = sr.ReadLine();
}
}
}
And it reads the streams from a Process (cmd.exe). When the user closes the cmd.exe window, it causes the CPU usage to jump to 100%. When playing with the debugger I see that it stops on the sr.ReadLine() and never returns. Because this is watching both the StandardErrorStream and the StandardOutputStream it uses 100% on both cores.
Here's some more code of the project if you need it.
[DllImport("User32")]
private static extern int ShowWindow(int hwnd, int nCmdShow); //this will allow me to hide a window
public ConsoleForm(Process p) {
this.p = p;
p.Start();
ShowWindow((int)p.MainWindowHandle, 0); //0 means to hide the window.
this.inStream = p.StandardInput;
this.outStream = p.StandardOutput;
this.errorStream = p.StandardError;
InitializeComponent();
wr = new watcherReader(watchProc);
wr.BeginInvoke(this.outStream, null, null);
wr.BeginInvoke(this.errorStream, null, null);
}
public void start(string[] folders, string serverPath) {
this.inStream.WriteLine("chdir C:\\cygwin\\bin");
this.inStream.WriteLine("bash --login -i");
this.inStream.WriteLine("");
}
//code example from http://geekswithblogs.net/Waynerds/archive/2006/01/29/67506.aspx it is
//to make the textbox autoscroll I don't understand what it does, but it works.
#region autoscroll
[DllImport("User32.dll", CharSet = CharSet.Auto, EntryPoint = "SendMessage")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
const int WM_VSCROLL = 277;
const int SB_BOTTOM = 7;
private void txtOut_TextChanged(object sender, EventArgs e) {
IntPtr ptrWparam = new IntPtr(SB_BOTTOM);
IntPtr ptrLparam = new IntPtr(0);
SendMessage(((RichTextBox)sender).Handle, WM_VSCROLL, ptrWparam, ptrLparam);
}
#endregion
private void ConsoleForm_FormClosed(object sender, FormClosedEventArgs e) {
this.stop = true;
try {
this.p.Kill();
} catch (InvalidOperationException) {
return;
}
}
Another interesting this is that it doesn't always hide the cmd window like it's supposed to. It hides it the first time, and then the second (or after) it won't hide it. This is when the user can close the cmd.exe window and cause the readline to act funny. It also never reads the last line outputted to cmd unless it exits.
Any suggestions on how to fix this?
I would change:
while(true)
to:
while(!sr.EOS) {
}
It is a better way to check to end the loop.
Whenever you have a while(true) loop in your code you're going to peg your cpu (or at least one core) at 100%, unless you also have a way to break out of the loop. In your case, you do have a return statement, but at no point in the loop do you ever do anything to the stop variable guarding it.
This seems like an interesting issue here. At first glance, it would appear that ReadLine has an issue with the handle being closed from under it while it's trying to read data, and thus would seem to be a bug in the Framework. However, I'm not convinced that easily that it's a bug in the .Net framework...
However, there are a couple low level issues here.
The other answers you have got so far all suggest you modify the while loop. I would do this as well, but I don't think this is the root of your problem. You do not need a sleep in there, because you will get your waitstate from the ReadLine(), unless there is no data to read, and it just returns a failue, THEN you will 'tight-loop'. So, make sure you are checking any and all error states during this loop.
If you do not, I can see issues.
If everything else is working as it should, then if I were you, I would start by trying to identify if you can duplicate it outside of your program with a small demo program. I'm sure there is plenty of error checking in the Framework's Stream handling. However, it looks like you are running some stuff from Cygwin, and that's the output you are reading from the cmd shell.
Try making a simple app that just spits out data to stdout, and stderr, and then make sure the app closes while you are still reading..
Also use the debugger to see what line== after the failure occurs.
Larry
Having while(true) with no sleep in the loop will cause 100% CPU usage.
You need to sleep for some amount of time or break out of the loop at some point so the CPU can do something else.
At the very least you should be doing something along the lines of:
while (sr.Peek() >= 0)
{
Console.WriteLine(sr.ReadLine());
Thread.Sleep(0);
}
I've written a c# application to run an external program and i've redirectet it's output to a richtextbox in my form. I've created the process using the following settings
p1.StartInfo.RedirectStandardOutput = true;
p1.OutputDataReceived += new DataReceivedEventHandler(outputreceived);
and in the outputreceived event
void outputreceived(object sender, DataReceivedEventArgs e)
{
if (!string.IsNullOrEmpty(e.Data))
{
richTextBox1.Invoke(new UpdateOutputCallback(this.updateoutput),
new object[] { e.Data });
}
}
void updateoutput(string text)
{
int len = text.Length;
int start = richTextBox1.Text.Length;
richTextBox1.Text += text + Environment.NewLine;
richTextBox1.Select(start, len);
richTextBox1.SelectionColor = System.Drawing.Color.White;
richTextBox1.Select(richTextBox1.Text.Length, 0);
richTextBox1.ScrollToCaret();
}
Now the thing is though it is working, but my main form which contains the textbox, hangs if the output is huge from the application. I think each time the invoke call leads to repainting of the form, which happens very frequently. Is there any alternative so that i can see the updates to the textbox as they happen and also keep the form completely active?
Update:
I think I got my answer, I used BeginInvoke when I should have used Invoke.
Update 1:
I tried both BeginInvoke and Suspendlayout but it is not giving me the desired functionality, what happens is that the process has returened all the standardoutput to the string, but the thread which is responsible for updating the text is taking it's own time to print the data. Can i do any thing to it?
Since you've already solved your problem, I'll just note that it will be faster if you use rtb.AppendText (instead of Text += ...) and use pinvoke to scroll to the bottom:
private const int WM_VSCROLL = 0x115;
private const int SB_BOTTOM = 7;
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam,
IntPtr lParam);
// ...
// Scroll to the bottom, but don't move the caret position.
SendMessage(rtb.Handle, WM_VSCROLL, (IntPtr) SB_BOTTOM, IntPtr.Zero);
You might want to try
richTextBox1.BeginInvoke()
rather than
richTextBox1.Invoke()
That will at least make the call Asynchronous. Still not sure if that will cause the UI thread to lock while the updates are being painted.
Try to suspend and resume layout of richTextBox1
void updateoutput(string text)
{
try
{
richTextBox1.SuspendLayout();
int len = text.Length;
int start = richTextBox1.Text.Length;
richTextBox1.Text += text + Environment.NewLine;
richTextBox1.Select(start, len);
richTextBox1.SelectionColor = Color.White;
richTextBox1.Select(richTextBox1.Text.Length, 0);
richTextBox1.ScrollToCaret();
}
finally
{
richTextBox1.ResumeLayout();
}
}
Is there any alternative so that i can see the updates to the textbox as they happen and also keep the form completely active?
I think you should use Debug.Print to view what's going on instead.
It is an old post, but maybe somebody still looking for it like I did.
You also can do, like "for(writeToTextbox % 10 == 0)" then invoke.
In this case it will be updated only every 10 times.
UPDATE: sorry for the misspelling! (wirte -> write) and thanks for "HaveNoDisplayName" to show it to me!