AutomationFocusChangedEventHandler interfere with external program (world of tanks) - c#

By adding a focus changed event handler to windows in my program using:
Automation.AddAutomationFocusChangedEventHandler(myHandler)
an external program is unable to run properly. When my program is running and is listening for events, the launcher of world of tanks is unable to start the world of tanks game client. This is problematic as my program is supposed to run 24/7 on multiple computers, and when I know it interfers with one program, it is likely that it can interfer with others.
The code of interest:
public static void SetWindowFocusChangeSubscriber()
{
AutomationFocusChangedEventHandler focusHandler = new AutomationFocusChangedEventHandler(OnFocusChange);
Automation.AddAutomationFocusChangedEventHandler(focusHandler);
}
private static void OnFocusChange(object src, AutomationFocusChangedEventArgs e)
{
return;
}
So does anyone know why this is? And how to fix it? Do I need to avoid using the Automation library?
Edit: Oh and btw, my program is in no way affiliated with world of tanks, or wants to interact with it. It just wants to detect when the active window changes.

Related

C# Updating log textbox while running

I have spent the past few days working on bot for an MMO. It runs in one big loop, with 1-2 other smaller loops inside. So far its going great. When its running it is set to update a richtextbox with what it is currently doing, just so I can easily troubleshoot later.
My problem is while its active and looping it does not auto update the textbox until it has finished everything it is doing. Which is hard when its set in an infinite loop. I would like to be able to run the bot with the main program window on the other monitor giving me updates as it goes along.
The whole program seems to freeze up and I cant interact with it at all while running. This also causes problems when I want it to stop. The only way I have of stopping it at the minute is to click Stop in visual studio.
I have tried searching around, but I have no idea what to search for. I hope I explained it well enough.
Thanks in advance.
This would be a nice read :
http://www.beingdeveloper.com/use-dispatcher-in-wpf-to-build-responsive-applications/
To summaries
You can send in a delegate fx, which is responsible for a formatter or writter. In you implemetation it would be the one which does AppendText. and make sure the Richtextbox.AppendText is within Dispatcher.Invoke()
Code Sample
class BotRand
{
//Write Event is delegate
public execute(WriteEvent writeFx)
{
//Crawl
writeFx("message");
}
}
class MainWindow : Window
{
void WriteFunc(object message, EventArgs outline)
{
Dispatcher.Invoke(new Action(() => richText.AppendText(message));
}
}
This should help you start your search more effectively.
Thanks,

How to monitor focus changes?

Well Sometimes I am typing and very rarely it happens that something steals focus, I read some solution (even a VB watch) but they don't apply to me. Is there any windows-wide 'handle' which handles ANY focus changes?
It doesn't matter in which language, C, C++, VB.NET, C#, Anything .NET or windows related, Batch, PoweShell, VBS Script... As Long as I am able to monitor every focus change and log it into a file/cmd window/visual window.
Something like:
void event_OnWindowsFocusChange(int OldProcID, int NewProcID);
would be very usefull. Or maybe there are tools for this already (which I can't find?)
One way would be to use the windows UI Automation API. It exposes a global focus changed event. Here is a quick sample I came up with (in C#). Note, you need to add references to UIAutomationClient and UIAutomationTypes.
using System.Windows.Automation;
using System.Diagnostics;
namespace FocusChanged
{
class Program
{
static void Main(string[] args)
{
Automation.AddAutomationFocusChangedEventHandler(OnFocusChangedHandler);
Console.WriteLine("Monitoring... Hit enter to end.");
Console.ReadLine();
}
private static void OnFocusChangedHandler(object src, AutomationFocusChangedEventArgs args)
{
Console.WriteLine("Focus changed!");
AutomationElement element = src as AutomationElement;
if (element != null)
{
string name = element.Current.Name;
string id = element.Current.AutomationId;
int processId = element.Current.ProcessId;
using (Process process = Process.GetProcessById(processId))
{
Console.WriteLine(" Name: {0}, Id: {1}, Process: {2}", name, id, process.ProcessName);
}
}
}
}
}
You can monitor focus changes with a hook. SetWindowsHookEx(), using the WH_SHELL hook gets it done. The callback gets the HSHELL_WINDOWACTIVATED notification.
This isn't easy to get going, particularly in a managed language since it requires a DLL that can be injected. Nor could you reliably tell the difference between an intended focus change or a process shoved the window and stole the focus. Which Windows tries to prevent but there's a backdoor called AttachThreadInput() that fools that code.
It is never difficult to tell what process does this. After all, it tried to activate one of its windows. Uninstalling that program is the simple and best fix.

Library works when called in Form1, but not from anywhere else

I have this library http://www.codeproject.com/KB/cs/globalhook.aspx
I've downloaded it and compiled it to DLL.
At first I had a weird problem that it haven't worked in my project, but it did (in the exact same code) worked in the demo project, but it was fixed by applying what the following message said:
http://www.codeproject.com/KB/cs/globalhook.aspx?msg=3505023#xx3505023xx
Note: I'm working with .NET 4, VS 2010 Ultimate
Well, I have a file Form1.cs, which is my main form for my app.
I have other files: Client.cs, Script.cs, Keylogger.cs - no, it's not an evil keylogger - It's for a school presentation about security\antiviruses etc.
Keylogger.cs has one static class and here's the code:
public static class Keylogger
{
static private StreamWriter sw = null;
static private System.Timers.Timer t = null;
static public bool Started = false;
static public void Start(string Location)
{
Started = true;
sw = new StreamWriter(Location, true, Encoding.Default, 1);
HookManager.KeyPress += HookManager_KeyPress;
t = new System.Timers.Timer(3600000);
t.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => sw.WriteLine(Environment.NewLine + "1 HOUR PASSED");
t.Start();
}
static public void Stop()
{
if (!Started)
throw new Exception("Keylogger is not operating at the moment.");
Started = false;
HookManager.KeyPress -= HookManager_KeyPress;
t.Dispose();
sw.Dispose();
}
static private void HookManager_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 8)
sw.Write("{BACKSPACE}");
else
sw.Write(e.KeyChar);
}
}
The Client class isn't static - it manages a TCP connections with a server, and send all received data to Script.RunScript(string scr) (static method).
Well, Script.RunScript should invoke Keylogger.Start(string location) for some input (STARTLOGGING c:\log.txt)
And invoke Keylogger.Stop() for some input (STOPLOGGING)
Well, everything is good, it invokes Start, but it doesn't work.
It does the whole process, (timer, event, streamwriter etc) but when I press something - the whole computer freeze for a couple of seconds and nothing happened (it doesn't even invoke KeyPress) - it happens only the first time. any other time - it simply ignores my keypress.
THE FUNNY THING IS - if I call Start from my mainform (in the ctor, on a button click event) - IT DOES WORK ! without any lag.
I did try different events (MouseDoubleClick, MouseMove) and all had the same problem.
Thank you, Mark !
The delay followed by the UI getting responsive again is a strong sign of the underlying cause of the problem. You see Windows healing itself, noticing that the callback isn't being responsive. It automatically disables the hook.
The hard requirement you probably violate is that the SetWindowsHookEx() call must be made from a thread that pumps a message loop. So that Windows can break in on a keypress and call the callback. That works fine when you called the Start() method from a button click, the Click event runs on the UI thread of your program.
But probably not when you this call is made from a networking event. They tend to run on a threadpool thread. It isn't clear from your snippet, you didn't post the code. The generic fix for a problem like this is using Control.BeginInvoke() to marshal a call from a worker thread to the UI thread. You'll find a good description of it in the MSDN library article as well as many, many answers here at stackoverflow.com
Fwiw, the original code got broken due to changed behavior in the .NET 4 version of the CLR. It no longer fakes the native module for assemblies. The workaround is good enough, it only needs a valid module handle. The actual one doesn't matter since this is not a global hook.
I think your best bet is to not write to the network on UI events, but instead have your logger write to a local file or in-memory database or similar, and then have a timer that periodically writes the content of that message to the server. That way you can both send chunkier messages to the server (improving performance on both machines) as well as have the ability to run the network call on a background thread, which makes the UI feel snappier.

Displaying a form locks up mono

I've got a mono app written in c# and executed on a Mac using "mono myapp.exe"
The app itself is a "Windows Application" when viewed from the project properties, but it doesn't always show a window. In program.cs, there is a static Main:
static void Main(string[] args) {
UserClient client = new UserClient();
client.Start(args);
}
public class UserClient {
public void Start(string[] args) {
// Talk to server, listen for instructions, etc.
....
// Launch the "Stay Alive" thread
// Just a thread that Sleeps/Loops watching for an exit command; mainly used to keep the process alive
}
}
Inside the UserClient's Start method, there is a piece of code that continuously monitors a server which gives it instructions to do things. One of the things it does is optionally displays a message using a windows form.
When the server instructs the process to display a message, it instantiates a form, displays it using frm.ShowDialog() and then after 30 seconds, a timer on the form runs Close() and the frm then gets disposed. However, when this happens, on my Mac I see an application title bar saying "mono" and a new icon on my dock bar for the mono app. After about 2 minutes the mono process in Activity Monitor shows "Not Responding." This eventually will prevent the user from logging out, shutting down, etc. (because Mac OS can't kill mono gracefully).
ON THE OTHER HAND... if the server never tells the process to display that form, everything runs fine and dandy: a dock icon never shows up (which is good!), mono title bar never shows up and the mono process continues to run happily, not preventing the system from shutting down or rebooting.
Anyone experienced this or have ideas on what's causing it? My guess is that it's a new GUI thread being created by the form which isn't ever being shutdown and is somehow causing a lockup, though I'm unsure of how to handle it.
Thanks for any suggestions.
Update:
Here's some code to easily reproduce and see this happening. I realize that this seems kind of "non-standard." Having said that, the below works perfectly in a Windows environment and provides the desired result of not showing an icon in the task area except when showing a message. Currently, using Application.Run and simply doing frm.ShowDialog() produce exactly the same result.
In the end what we need is to be able to display the form, then destroy the form and any associated icon from the dock. I suspect the GUI is starting a thread which isn't ever being disposed, which is why the dock icon remains. Is there a way to make sure the GUI thread is taken care of?
static class Program {
static void Main() {
StartupClass s = new StartupClass();
s.start();
}
}
public class StartupClass {
Thread stayAliveThread;
public void start() {
// Stay alive thread
stayAliveThread = new Thread(stayAliveLoop);
stayAliveThread.Start();
// This shows a form and would normally be used to display temporary and brief messages to the user. Close the message and you'll see the undesired functionality.
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
Application.Exit();
Application.ExitThread();
}
/// <summary>
/// Keep the app alive.
/// </summary>
private void stayAliveLoop() {
while (true) {
Thread.Sleep(10000);
// In the real project this method monitors the server and performs other tasks, only sometimes displaying a message.
}
}
}
I feel I'm missing several things. Most notably
[STAThread]
static void Main(string[] args) { //....
Also see this answer: Windows Forms and ShowDialog problem
I can't see anything like initializing message loop for windowed application. I.e. in windows forms case something like Application.Run(). If you do not have it, no wonder application freezes. In any case, posting more code could be helpful, as stated in comment.
In the end, I couldn't resolve this. I created a process that launched another app which displayed the message form. Not really a true answer, but the solution I had to go with.

c# console application sub windows

I'd like for a single console application to spawn other console windows and output to different ones at different times inside of a C# console application. Preferably within one console application, I spawn some other consoles, write to them, and close them during the finally block of the original console application.
What's the ideal way to do this in C#?
I don't believe you can do this with a regular console application. The closest you could come would be to create a your own form in WinForms/WPF which behaved in roughly the same was as a normal console window.
I suppose you could spawn extra processes which each had their own console, and write to them via network connections or named pipes etc... it would be pretty ugly though.
You can do this with Auto/Manual EventWaitHandles in C# combined with countless other techniques. However, you should probably step back and see what you are trying to accomplish and see if a winform app would be a better fit. Maybe post more details and ask for ideas.
A single process can only ever have one true Standard In, Error and Out.
You can fake different ones, especially in .Net because after all they are presented as managed streams which would be fine at the push/pull and of the pipe. The problem is the output/input end i.e. the bit you might be piping to a file, or where you are requesting user input. These simply won't play ball since the OS supplies no multiplexing method itself.
Using simple means at best you could do something that sent output to multiple different windows which looked much like a console window.
With much complexity you would handle reading from them too. In essence you are writing a window which pretends to be a console, and getting it reasonably close to all the little intricacies of console windows is (increasingly) hard.
It would be simple to have (say) a fake console per thread by creating a class like so. I only bother with Out, In and Err follow easily from this.
public class MultiplexByThreadConsole : IDisposable
{
private readonly TextWriter originalOut;
private readonly TextWriter myOut = new IndividualMultiplex();
public MultiplexByThreadConsole()
{
this.originalOut = Console.Out;
Console.SetOut(this.myOut);
}
public void Dispose()
{
Console.SetOut(this.originalOut);
}
private class IndividualMultiplex : TextWriter
{
[ThreadStatic]
private readonly TextWriter actual;
// override all the required functions and any
// others you want to wrap
public override void Write(char c)
{
if (actual == null)
{
actual = MakeWhateverYouReallyWantToOutputTo();
}
actual.Write(c);
}
}
}
Then somewhere in Main (or wherever) do:
using(new MultiplexByThreadConsole())
{
// off you go all threads during this get their own faked console.
}
You would likely keep the In/Out/Err all pointing to some common objects writers/reader which was itself the fake console.
This is however pretty nasty. I would say that, if you truly want to launch things that look like separate consoles then you should actually do that and launch a new process for each one with a glue back end to manage them (somewhat similar to the concept of Chrome's back end processes per tab).

Categories