I have a windows mobile app that look like this:
class Program
{
static void Main(string[] args)
{
RunHook runHook = new RunHook();
}
}
class RunHook
{
private HookKeys hook;
public RunHook()
{
hook = new HookKeys();
hook.HookEvent += EventForHook;
}
private void EventForHook(HookEventArgs e, KeyBoardInfo keyBoardInfo,
ref Boolean handled)
{
if ((keyBoardInfo.scanCode == 4) && (keyBoardInfo.vkCode == 114))
handled = true;
}
}
It will create a hook into the keyboard (I know that is frowned on by some). My issue is that I need the Main method to never return. This is going to run on devices owned by my company and we are using this to disable the phone hardware keys.
This seems like it should be simple, but I am stuck on it.
On normal .NET I would just call Console.Readline(), but that does not work on Windows Mobile Compact Framework. I have also tried Thread.Sleep(0), but it does not work either.
Thanks for any feedback.
Thread.Sleep(0) sleeps for zero milliseconds.
You probably want Thread.Sleep(Timeout.Infinite).
You might also consider creating an EventWaitHandle:
class Program
{
static public ManualResetEvent StopMain;
static void Main(string[] args)
{
StopMain = new ManualResetEvent(false);
RunHook runHook = new RunHook();
StopMain.WaitOne(); // waits until signalled
}
}
Then, if you were ever ready to exit Main(), you could call (from another thread):
Program.StopMain.Set();
If it going to run on devices that are owned by your company then why not run a small windows program in background. I mean just hide the window. Let it sit in your task bar.
Click on this link for more information on use of notification icon in CF.
not sure this will help but with native code youd call
LRESULT CallNextHookEx(
HHOOK hhk,
int nCode,
WPARAM wParam,
LPARAM lParam
);
in your handler to execute the default handling behaviour, havent tested this but i think if you dont call the next handler in the chain, nothing will happen
more info:
http://msdn.microsoft.com/en-us/library/ms644974%28VS.85%29.aspx
.
the link contains some managed code samples which may help
hth
Related
I'm trying to simulate a keystroke ("z") on another window, a game in particular.
I've implemented in my program a simple timer that sends the key with PostMessage every 1000ms, but the "action" related to the pressing of that key doesn't start.
I've analysed the Messages sent to the window of the game with Spy++, but the strange thing is that i can see the exact sequence of messages (KEYDOWN, CHAR and KEYUP), whether i press it manually or send it through my application. Obviously if i press "z" manually the game's function gets called correctly.
Here i report the messages that i get from Spy++, the first 3 are from me hitting z manually, the last 3 are from my software.
Messages from Spy++
And here i include the code that i'm using
[DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, uint lParam);
private void SendKeys(IntPtr proc_hwnd, IntPtr key)
{
PostMessage(proc_hwnd, 0x100, key, 0x002C0001);
Thread.Sleep(100);
PostMessage(proc_hwnd, 0x101, key, 0xC02C0001);
}
Process[] proc;
private void Button1_Click(object sender, EventArgs e)
{
proc = Process.GetProcessesByName("Proc_name");
if (proc.Length == 0)
{
MessageBox.Show("No process found");
return;
}
tmr_raccogli.Interval = (int)(num_raccogli.Value * 1000);
tmr_raccogli.Start();
}
private void tmr_raccogli_Tick(object sender, EventArgs e)
{
SendKeys(proc[0].MainWindowHandle, (IntPtr)Keys.Z);
}
I don't get why it's not working since from that point of view the two actions are identical.
i don't have an exact answer but i might able to guide you in the right direction.
The focus and foreground state of your window maybe important as well as the input thread.
SetFocus
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setfocus
SetForegroundWindow
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setforegroundwindow
AttachThreadInput
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-attachthreadinput
Your windows receives the messages but i decides to ignore them, this depends on how the implementation of windows msgs is programmed in the target. I can remember creating something similar and AttachThreadInput fixed most of my code interoperability problems.
I have a small launcher program, it loads a Splash screen on it's own thread and displays it. If a set of conditions are met it needs to launch another application and keep the splash screen visible till the other application says it is ok to close the splash screen.
The Launcher will always have a lifetime that starts before Child App and ends after Child App closes.
Here is some snippets of relevant code
The common DLL:
namespace Example.Common
{
public partial class SplashScreen : Form
{
public SplashScreen()
{
InitializeComponent();
}
static SplashScreen splashScreen = null;
static Thread thread = null;
static public void ShowSplashScreen()
{
// Make sure it is only launched once.
if (splashScreen != null)
return;
thread = new Thread(new ThreadStart(SplashScreen.ShowForm));
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
// A static entry point to launch SplashScreen.
static private void ShowForm()
{
splashScreen = new SplashScreen();
Application.Run(splashScreen);
}
// A static method to close the SplashScreen
static public void CloseForm()
{
splashScreen.Close();
}
}
}
The Inital Launcher:
/// <summary>
/// This application is a small launcher to launch the real graphical launcher. It is small and lightweight and should be rarely be updated.
/// It will call the ProgramLauncher, the program launcher will return in it's status code the PID of the instance it launched or -1
/// if no subsequent program was started.
/// </summary>
[STAThread]
static void Main()
{
//Show the Splash screen;
Example.Common.SplashScreen.ShowSplashScreen();
//(Snip)
if (rights == UserRights.None)
{
SplashScreen.CloseForm();
MessageBox.Show("Your user does not have permission to connect to the server.", "Unable to logon", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
//If the user has full desktop access, give it to them and launch a new instance of the launcher.
else if (rights.HasFlag(UserRights.FullDesktopAccess))
{
Process explorer = new Process();
explorer.StartInfo.FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "explorer.exe");
if (explorer.Start() == false)
{
MessageBox.Show("Explorer failed to start.");
}
else
{
//Close the splash screen.
SplashScreen.CloseForm();
//If the user can shadow start a new instance of the launcher inside explorer.
if (rights.HasFlag(UserRights.ShadowNormalUser) || rights.HasFlag(UserRights.ShadowDemoUser))
{
//Start a new copy of the program so people can use it to shadow easily.
var shadowProc = new Process();
shadowProc.StartInfo.FileName = "ProgramLauncher.exe";
shadowProc.StartInfo.UseShellExecute = false;
shadowProc.Start();
}
explorer.WaitForExit();
}
}
else
{
Process programLauncher = new Process();
programLauncher.StartInfo.FileName = "ProgramLauncher.exe";
programLauncher.StartInfo.UseShellExecute = false;
//Launch the graphical launcher.
programLauncher.Start();
programLauncher.WaitForExit();
//Check to see if the graphical launcher launched some other process.
if (programLauncher.ExitCode >= 0)
{
//If there was a pid, don't close the micro launcher till after it closes.
Process runningProcess = Process.GetProcessById(programLauncher.ExitCode);
runningProcess.WaitForExit();
}
}
}
What is the easiest way to let ProgramLauncher close the SplashScreen instance MicroLauncher created?
You need to have SplashScreen pass it's window handle (HWND) to ProgramLauncher. Then, ProgramLauncher can use the SendMessage winapi function to send a WM_SYSCOMMAND message to the target window:
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_CLOSE = 0xF060;
SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
In WinForms, you can get a form's native handle with Handle.
The platform invoke code for SendMessage is here.
At least I don't see an easier way now, but I think it's easier than any IPC mechanism out there.
There are lots of ways of doing this, with pros and cons to each. Possibly the easiest way is to redirect standard output from your ProgramLauncher process and wire it up to an event in the MicroLauncher application (see here for an example). From your ProgramLauncher program, you write a certain message to standard output. When that message is received by MicroLauncher, you close the window.
Another option is to pass the HWND of your splash screen to ProgramLauncher as a command-line parameter, then ProgramLauncher can use SendMessage(WM_SYSCOMMAND, SC_CLOSE) to close the window (see here for an example).
You can also look into methods of IPC, sending custom Windows messages, or probably a thousand other possibilities, but those two ideas may get you started.
Easiest way I can think of: have the child app create a named mutex, and have the parent app wait until someone's created it, checking every now and then.
Not very elegant and open to abuse (where another app intentionally creates a mutex with the same name), but in practice, I doubt that'll be a problem.
Hello all
I am working with .Net 2 at console application.
I have a method that do a long job. it name is:
public void DO(){....}
i want when key-press to stop the job.
how i do it elegant?
with event?
thanks for your help
One of the solution can be simply run DO(..) in another thread, and listen for the key press on main thread Console.ReadLine() or any other overload. At the moment you get a key, signal to DO(...) method's thread to stop.
EDIT
Simple, very basic example (I see you're talking about C# 2.0) by using volatile bool variable can find here:
Sample
Like Tigran said, just use a Thread.
Using events freezes the application till the next event is listened.
private static bool abortthread = false;
public static void main()
{
new Thread(new ThreadStart(DO)).Start();
Console.ReadLine();
abortthread = true;
}
private static DO()
{
while(true)
{
if(abortthread)
return;
}
}
I am using the following code to get mouse messages on the current process.
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
For some reason when this code runs the mouse get slow for several seconds and then back to normal.
Any ideas?
Thanks
EDIT - hook method
private static IntPtr mouseEvent(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
LastLeftClick = new ClickInfo { Time = DateTime.Now, X = hookStruct.pt.x, Y = hookStruct.pt.y };
}
return CallNextHookEx(hookID, nCode, wParam, lParam);
}
public class ClickInfo
{
public int X { get; set; }
public int Y { get; set; }
public DateTime Time { get; set; }
}
I had the same problem (only it's c++ project, not c#) and resolved it by changing hook from WH_MOUSE_LL to WH_MOUSE (from low-level to normal level). For WM_LBUTTONUP and WM_RBUTTONUP messages it works ok.
The thing that amuses me is that code with WH_MOUSE_LL was doing fine at the time I wrote it (no mouse freezes etc.) It seems like some security update for Windows changed the behavior of the mouse hooks and previously fine code become a problem.
I am sorry to follow up after such a long time but I have solved the issue by spawning a separate thread which handles the hook (I have not added everything to the code as it also translates messages but the main idea should be clear):
public Form1()
{
InitializeComponent();
Thread thread = new Thread(HookThread);
thread.IsBackground = true;
thread.Start();
}
private void HookThread()
{
_hookControl = new Control();
IntPtr handle = _hookControl.Handle;
_hookProc = new HookProc(HookFunction);
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
_hook = SetWindowsHookEx(HookType.WH_MOUSE_LL, _hookProc, GetModuleHandle(curModule.ModuleName), 0);// (uint)AppDomain.GetCurrentThreadId());
}
Application.Run();
UnhookWindowsHookEx(_hook);
_hook = IntPtr.Zero;
}
private IntPtr HookFunction(int code, IntPtr wParam, IntPtr lParam)
{
if (code < 0)
{
//you need to call CallNextHookEx without further processing
//and return the value returned by CallNextHookEx
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
int msg = wParam.ToInt32();
string messages = string.Join(", ", _messageMapping.Where(t => t.Item1 == msg).Select(t => t.Item2));
if (string.IsNullOrWhiteSpace(messages))
messages = msg.ToString();
Trace.WriteLine($"Messages: { messages }");
//return the value returned by CallNextHookEx
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
You can terminate the thread from any other thread by calling BeginInvoke on the created _hookControl:
_hookControl.BeginInvoke(((Action)(() => Application.ExitThread())));
What does your hook procedure look like?
If your process only has one UI thread, use a Message Filter instead:
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.addmessagefilter.aspx
By setting a low level hook responsiveness of the mouse now becomes dependent on your main thread being responsive and a common mistake made is to set the hook early in the start-up process.
SetHook
LongRunningStartupProcess
Mouse isn’t responsive until here
During start-up it is best to dispatch the hook onto the thread so it happens at the end of the start-up process. Dispatcher.CurrentDispatcher.BeginInvoke(new Action(SetHook));
DispatchSetHook
LongRunningStartupProcess
SetHook(callback)
Mouse becomes responsive
This still has ongoing management issues within your application to ensure the main thread doesn’t do any long running processes as that will lock the mouse up too. This can easily be verified by setting the hook and then doing a Thread.Sleep on the main thread.
When you receive the hook event, turn off the book, then do your work, and if really still needed, put the hook back on.
This will stop the mouse from lagging.
Only stay hooked when you really need to.
Your hook proc is expensive; you just need to figure out why and how to fix it.
Even though though the code looks very minimal i suspect that there is some initial C# interop expense triggering the delays, perhaps due to JIT or paging.
If you change the code to do as much processing as possible off of this thread the problem should go away. as a C++ developer I even worry about the Marshal.PtrToStructure since low-level hooks are very sensitive and I can't say off the top of my head that this operation is guaranteed to be so cheap that it wouldn't impair mouse movement.
I've used low-level mouse hooks quite a bit in the past (in C++) and have never had problems unless the hook procedure itself is expensive. In C++ I try to avoid doing anything more than a PostMessage to an HWND that does the rest of the processing.
System.Diagnostics.Process exposes a StreamWriter named StandardInput, which accepts only characters as far as I know.
But I need to send keystrokes as well, and some keystrokes don't map well to characters.
What should I do?
You are mixing input streams with control signals. A console process has a default input stream which you can control with the StandardInput, as you already know. But Ctrl-C and Ctrl-Break are not characters sent to the process through this stream, but instead they are instead control signals that the process receives using the registered signal handlers, see CTRL+C and CTRL+BREAK Signals:
By default, when a console window has
the keyboard focus, CTRL+C or
CTRL+BREAK is treated as a signal
(SIGINT or SIGBREAK) and not as
keyboard input.
To send fake signals to a process you can use GenerateConsoleCtrlEvent and send either CTRL_C_EVENT or CTRL_BREAK_EVENT. This API has no .Net equivalent, so you have to PInvoke it.
To use it from .NET you simply need to include the function definition:
const int CTRL_C_EVENT = 0;
const int CTRL_BREAK_EVENT = 1;
[DllImport("kernel32.dll")]
static extern bool GenerateConsoleCtrlEvent(
uint dwCtrlEvent,
uint dwProcessGroupId);
There's an input Simulator found here on Codeplex which may do just the job for you.
I am working on a sample code and will post back here shortly, bear in mind the Input Simulator is similar to what was found in the link supplied by Remus...
Edit: I have found that there is a limitation with this, you can definitely get away with the typical System.Windows.Forms.SendKeys.Send method, it does work effectively! , but, the process must have
No redirections of the streams
Cannot be hidden window (this is where it will fail, since the window's handle is nowhere to be seen, no way of bringing it to the foreground to make it active!)
A window showing the process for this to be effective!
In your case, it's a matter of finding the window, set it active via pinvoke 'SetForegroundWindow', and send the sequences ^{BREAK} which sends the Ctrl+Break signal to the process which does work very well (especially if the process is a command line program/batch file). Here's an article on CodeProject that does this exactly and mirrors the SendKeys...I have yet to paste some code into this to demonstrate ....
Edit#2: Actually I am quite surprised...as this code will show (proof of concept)...it is using:
InputSimulator (as mentioned previously)
A windows form that consists of a button, when the form is loaded it automatically runs the class. Upon clicking the button, it posts a ctrl-break to the hidden process
The output stream is indeed redirected and is a hidden window.
The weird thing, is the output is being captured but does not show the results in the debug window, in real-time that is, it is buffered (I guess) until the process terminates, the whole output is shown...
I cheated a bit on the FindWindow API call, because I knew the window's title was and was somehow, able to bring it to the foreground, and using the InputSimulator to send the keystrokes to it...or use the traditional plain old SendKeys function...the reason I had the Thread.Sleep is to ensure that the keystrokes are sent in order to be 'pushed into the keyboard queue of the "active foreground window", which despite that, is hidden'
I used the 'netstat -e 5' command to loop forever, refreshing the results every 5 seconds until it receives a 'Ctrl+C' to break the infinite loop.
public partial class Form1 : Form
{
private TestNetStat netStat = new TestNetStat();
public Form1()
{
InitializeComponent();
using (BackgroundWorker bgWorker = new BackgroundWorker())
{
bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
bgWorker.RunWorkerAsync();
}
}
void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("BGWORKER ENDED!");
}
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
netStat.Run();
}
void btnPost_Click(object sender, EventArgs e)
{
netStat.PostCtrlC();
System.Diagnostics.Debug.WriteLine(string.Format("[{0}] - {1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), this.netStat.OutputData.Replace(Environment.NewLine, "")));
}
}
public class TestNetStat
{
private StringBuilder sbRedirectedOutput = new StringBuilder();
//
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32")]
public static extern int SetForegroundWindow(IntPtr hwnd);
public string OutputData
{
get { return this.sbRedirectedOutput.ToString(); }
}
public void PostCtrlC()
{
IntPtr ptr = FindWindow(null, #"C:\Windows\System32\netstat.exe");
if (ptr != null)
{
SetForegroundWindow(ptr);
Thread.Sleep(1000);
WindowsInput.InputSimulator.SimulateModifiedKeyStroke(VirtualKeyCode.CONTROL, VirtualKeyCode.CANCEL);
// SendKeys.Send("^{BREAK}");
Thread.Sleep(1000);
}
}
public void Run()
{
System.Diagnostics.ProcessStartInfo ps = new System.Diagnostics.ProcessStartInfo();
ps.FileName = "netstat";
ps.ErrorDialog = false;
ps.Arguments = "-e 5";
ps.CreateNoWindow = true;
ps.UseShellExecute = false;
ps.RedirectStandardOutput = true;
ps.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
using (System.Diagnostics.Process proc = new System.Diagnostics.Process())
{
proc.StartInfo = ps;
proc.EnableRaisingEvents = true;
proc.Exited += new EventHandler(proc_Exited);
proc.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(proc_OutputDataReceived);
proc.Start();
proc.BeginOutputReadLine();
proc.WaitForExit();
}
}
void proc_Exited(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("proc_Exited: Process Ended");
}
void proc_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
{
if (e.Data != null)
{
this.sbRedirectedOutput.Append(e.Data + Environment.NewLine);
System.Diagnostics.Debug.WriteLine("proc_OutputDataReceived: Data: " + e.Data);
}
}
}
Nitpicky aside, I know that the netStat is running off the 'BackgroundWorker' thread, and I directly invoked the 'PostCtrlC' method from the main GUI thread...this is pedantic as a proof-of-concept code, but it does show that it needs to implement 'ISynchronizeInvoke' to make it thread-safe, that aside...it does indeed work.
Have you seen this great tool - AutoIt. This is a scripting tool. To send a backspace you would use Send("{BACKSPACE}")
This is a great tool and it can help in automating many manual clicks/double-clicks/etc.
Is this relevant to your question ?
If you have a Windows Forms window that you can send the keys to, then SendKeys might be an appropriate solution.
For pressing backspace and Ctrl+C, that should be
SendKeys.Send("{BACKSPACE}^C");