I want to create a software like a virtualkeyboard, you have a AlwaysTop Window and use this to put some data on another process/windows. In this case I will record all data on clipboard and compare if this data is compatible with a pattern (A### is the patern and A123 is compatible with the patern), if yes the application will put it in a listbox and the user can paste it on another process/windows (already open) clicking on item on list.
My question is about how to put this information on the last application/process used, I already started a prototype of code but the line indicated is wrong, on my code it's the currentprocess and need to be the last used before click on my form.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("user32.dll")]
static extern IntPtr SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("User32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
private void button2_Click(object sender, EventArgs e)
{
Process currentProcess = Process.GetCurrentProcess(); //this line is wrong
IntPtr hWnd = currentProcess.MainWindowHandle; //this line is wrong
if (hWnd != IntPtr.Zero)
{
SetForegroundWindow(hWnd);
ShowWindow(hWnd, 9);
SendKeys.Send("A123");
}
}
}
}
I get on simple solution, instead of get the process I just send the combination ALT+TAB and work for all cases that I need. Below the solution if anyone need in the future:
string old_clipboard = Clipboard.GetText();
Clipboard.SetText("A123");
SendKeys.SendWait("%{Tab}");
SendKeys.SendWait("^V");
Thread.Sleep(100);
Clipboard.SetText(old_clipboard);
Ps.: I put one delay because the SendWait works only on caller windows, as the target of ^V is another process it´s don´t work well.
Best regards. =)
Related
I found command System.Windows.Forms.SendKeys.Send() for sending keypress some key. This function work if open external app like a notepad and set focus and I will be see that my Key printed in this text field. How do same but with key down event, System.Windows.Forms.SendKeys.SendDown("A");, for example?
I tried call in Timer this command System.Windows.Forms.SendKeys.Send() but have runtime error associated with very fast taped.
You can't use the SendKeys class for that, unfortunately. You will need to go to a lower level API.
Poking a window with a keydown message
In Windows, keyboard events are sent to windows and controls via the Windows message pump. A piece of code using PostMessage should do the trick:
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
const uint WM_KEYDOWN = 0x0100;
void SendKeyDownToProcess(string processName, System.Windows.Forms.Keys key)
{
Process p = Process.GetProcessesByName(processName).FirstOrDefault();
if (p != null)
{
PostMessage(p.MainWindowHandle, WM_KEYDOWN, (int)key, 0);
}
}
Note that the application receiving these events may not do anything with it until a corresponding WM_KEYUP is received. You can get other message constants from here.
Poking a control other than the main window
The above code will send a keydown to the "MainWindowHandle." If you need to send it to something else (e.g. the active control) you will need to call PostMessage with a handle other than p.MainWindowHandle. The question is... how do you get that handle?
This is actually very involved... you will need to temporarily attach your thread to the window's message input and poke it to figure out what the handle is. This can only work if the current thread exists in a Windows Forms application and has an active message loop.
An explanation can be found here, as well as this example:
using System.Runtime.InteropServices;
public partial class FormMain : Form
{
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll")]
static extern IntPtr AttachThreadInput(IntPtr idAttach,
IntPtr idAttachTo, bool fAttach);
[DllImport("user32.dll")]
static extern IntPtr GetFocus();
public FormMain()
{
InitializeComponent();
}
private void timerUpdate_Tick(object sender, EventArgs e)
{
labelHandle.Text = "hWnd: " +
FocusedControlInActiveWindow().ToString();
}
private IntPtr FocusedControlInActiveWindow()
{
IntPtr activeWindowHandle = GetForegroundWindow();
IntPtr activeWindowThread =
GetWindowThreadProcessId(activeWindowHandle, IntPtr.Zero);
IntPtr thisWindowThread = GetWindowThreadProcessId(this.Handle, IntPtr.Zero);
AttachThreadInput(activeWindowThread, thisWindowThread, true);
IntPtr focusedControlHandle = GetFocus();
AttachThreadInput(activeWindowThread, thisWindowThread, false);
return focusedControlHandle;
}
}
The good news-- if SendKeys worked for you, then you might not need to do all this-- SendKeys also sends messages to the main window handle.
I have create a Window use WPF, I want to my Window always display on the top, So I just create a thread for it:
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
for (;;)
{
System.Threading.Thread.Sleep(3000);
this.Dispatcher.BeginInvoke(new Action(() =>
{
this.Activate();
this.Topmost = true;
}));
}
});
}
This will make sure my window go to front in every 3 seconds.
And when I open it under Visual Studio 2015, all fine, even when I open the Start Menu, it will close start menu and bring the window on top.But when I'm not use Visual studio open the application(just double click open the application), when I open start menu, the Window just flickering, not display on the top. What I miss? and how do I let it work as like open the application under Visual Studio 2015(I'm tested on Win10)?
EDIT: I somehow missed the point covered in the title. The point I make later of "Do not do it" still holds true though. It could cause problems for users of your application.
If you really need to though, this answer may be the one you are looking for. It discusses how to keep a window in front of everything. It is still a work around (just like most answers to your question).
Old Answer
I understand your problem as: you want your window to stay on top of all other windows. Similar functionality can be found in Ubuntu and The Google Play Music desktop application for Window's (see below).
To accomplish this, all you need to do is add Topmost="True" to your Window as demonstrated below (look at the last property).
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Topmost="True">
</Window>
Unless your actual problem "is what happens when two windows have that property set?" Then I would suggest reading this article (the same article that was referenced in the comments). It states the following:
"How do I create a window that is never covered by any other windows, not even other topmost windows?"
Imagine if this were possible and imagine if two programs did this.
Program A creates a window that is "super-topmost" and so does Program
B. Now the user drags the two windows so that they overlap. What
happens? You've created yourself a logical impossibility. One of those
two windows must be above the other, contradicting the imaginary
"super-topmost" feature.
If that functionality is really what you are after, I would suggest: do not do it. All other solutions are a workaround and could cause problems for consumers of your application.
I would have used interop to do this.
public class Interop
{
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hwind, int cmd);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
public static IntPtr GetWindowHandle(Window window)
{
return new WindowInteropHelper(window).Handle;
}
}
then use a timer:
private void Tick(object state)
{
this.Dispatcher.Invoke(() =>
{
IntPtr window = Interop.GetWindowHandle(this);
IntPtr focused = Interop.GetForegroundWindow();
if (window != focused)
{
Interop.SetForegroundWindow(window);
// Command 5 for show
Interop.ShowWindow(window, 5);
}
});
}
Code from
And for the part of your problem regarding the startmenu, just add a group policy.
Or you can make a interop to ´FindWindowEx´ to find the startbutton and disable it.
I agree with Jonas's answer but would modify it to use an event instead of a timer.
/// Get the topmost window handle
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
/// Trigger event when topmost window changed
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, TopmostWindowChangedDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
/// Set the topmost window
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
/// Show a window
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hwind, int cmd);
// Constant variables for topmost window changed event
private const uint WINEVENT_OUTOFCONTEXT = 0;
private const uint EVENT_SYSTEM_FOREGROUND = 3;
/// Keep track of the last topmost window with a name
private static IntPtr topWinHandle { get; set; }
/// Implementation of topmost window changed delegate
private TopmostWindowChangedDelegate TopmostWindowChanged { get; set; }
Then set up the handlers in one of your startup methods
// Set topmost window changed event handler
TopmostWindowChanged = new TopmostWindowChangedDelegate(WinEventProc);
// Set event hook for topmost window changed
IntPtr hook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, TopmostWindowChanged, 0, 0, WINEVENT_OUTOFCONTEXT);
And then move your window to topmost when the other topmost changes
/// Make sure this window stays on top
public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
// Get current window name from handle
IntPtr handle = GetForegroundWindow();
if(handle != YOUR_WINDOW'S_HANDLE)
{
// Move your window back to the top
SetForegroundWindow(YOUR_WINDOW'S_HANDLE);
ShowWindow(YOUR_WINDOW'S_HANDLE, 5);
}
}
I use this code to check whether my program is already open:
string RunningProcess = System.Diagnostics.Process.GetCurrentProcess().ProcessName;
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName(RunningProcess);
if (processes.Length > 1)
{ return true; }
It would, if the program is open, bring it to the floor and show it. How can I do? Thank you.
You have to import the following method:
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hwnd, int nCmdShow);
Then you can call this method this way:
ShowWindow(process.MainWindowHandle, 0);//Hide
ShowWindow(process.MainWindowHandle, 1);//Show
NOTE: The window can just be shown if it is minimized. It won't show it if it is in the background of an other window.
If you want to show a window that is in the background of an other one you have to import this method:
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
Then call it in the same way as ShowWindow:
SetForegroundWindow(process.MainWindowHandle);
NOTE: You can just set the foreground window if it is not minimized.
You can also combine both methods with IsIconic to call the right method:
[DllImport("user32.dll")]
static extern bool IsIconic(IntPtr hWnd);//Returns false if the window is minimized
The full code to show the mainwindow:
static void GotoProcess(Process process)
{
if (IsIconic(process.MainWindowHandle))
{
ShowWindow(process.MainWindowHandle, 1);
}
else
{
SetForegroundWindow(process.MainWindowHandle);
}
}
I'm running into a weird problem.
I have a WinForms application that opens another program (billing system emulator), sets it as a child window and then disables it. This works fine, the user cannot send any keys to the that child window, and the winforms application does its thing, sending commands to the child window.
However, it's been discovered that pushing the shift or control, even if the winforms application doesn't have focus, causes an error in the billing system emulator as they aren't valid keys. Users have taken to not using the shift or control keys while the winforms app runs but that's obviously not a practical solution.
My attempted solution was:
Global keyboard hook to capture when those keys are pressed.
Overriding OnKeyDown in the winforms application to stop those keys.
That however still doesn't solve the problem of the shift and alt keys being sent to the child window when the winforms app is not in focus. I can stop shift and alt globally while the winforms app is running but I don't think that is valid. So I need to somehow in the global hook stop the keypress for the winforms app and its children but allow globally. Any ideas/thoughts?
This is my code.
I don't think there's a good answer for your scenario... =\
Here's a hack you can try. It will "release" Control/Shift if they are down, then you send your message afterwards:
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int extraInfo);
[DllImport("user32.dll")]
static extern short MapVirtualKey(int wCode, int wMapType);
private void button1_Click(object sender, EventArgs e)
{
if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift)
{
keybd_event((int)Keys.ShiftKey, (byte)MapVirtualKey((int)Keys.ShiftKey, 0), 2, 0); // Shift Up
}
if ((Control.ModifierKeys & Keys.Control) == Keys.Control)
{
keybd_event((int)Keys.ControlKey, (byte)MapVirtualKey((int)Keys.ControlKey, 0), 2, 0); // Control Up
}
// ... now try sending your message ...
}
This obviously isn't foolproof.
I took a look at the only constructor of the globalKeyboardHook and looks like it is designed only for global hook. You can add another overload to hook into the current running module only like this:
class globalKeyboardHook {
[DllImport("kernel32")]
private static extern int GetCurrentThreadId();
[DllImport("user32")]
private static extern IntPtr SetWindowsHookEx(int hookType, KeyBoardProc proc, IntPtr moduleHandle, int threadId);
[DllImport("user32")]
private static extern int CallNextHookEx(IntPtr hHook, int nCode, IntPtr wParam, IntPtr lParam);
public globalKeyboardHook(bool currentModuleOnly){
if(currentModuleOnly){
proc = KeyBoardCallback;
//WH_KEYBOARD = 0x2
hhook = SetWindowsHookEx(2, proc, IntPtr.Zero, GetCurrentThreadId());
} else hook();
}
public delegate int KeyBoardProc(int nCode, IntPtr wParam, IntPtr lParam);
public int KeyBoardCallback(int nCode, IntPtr wParam, IntPtr lParam) {
if (nCode >= 0) {
Keys key = (Keys)wParam;
var lp = lParam.ToInt64();
//your own handling with the key
if ((lp >> 31) == 0)//Key down
{
//your own code ...
} else { //Key up
//your own code ...
}
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
KeyBoardProc proc;
//other code ...
}
//then use the new overload constructor instead of the parameterless constructor:
globalHook = new globalKeyboardHook(true);
NOTE: You can implement your own KeyDown and KeyUp event based on what I posted above (the comment your own code ...). After some searching I understand that the WH_KEYBOARD_LL supports global hook only while the WH_KEYBOARD is for thread hook only. That should be what you want instead of the WH_KEYBOARD_LL.
BTW, I doubt that the IMessageFilter which can be registered/added by your application can be used in this case. It also supports a PreFilterMessage method helping you to intercept any key and mouse messages at the application-level. You should try searching on that, it's easy to follow.
I am new to WINAPI and have figured out how to send a message to another program. The program I am using however I would like to be able to have it click on a specific button. From what I have learned by viewing Spy++ windows handles change for the programs every time they are reloaded and so do the handles for their controls. The control ID stays the same. After two days of trying to figure it out I am here.
under SendMesssageA if I specify the current handle as viewable by Spy++ and use that and run the code it works fine and clicks the button on my external application. I am attempting to use GetDlgItem as I have read that I can get the handle for the control (child window) using it. I am doing something wrong however since no matter what I do it returns 0 or 'null'.
How can I get GetDlgItem to return the child control handle so that I may use it to sendmessage to click that control in the external application?
Thanks for your help an input ahead of time.
[DllImport("User32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
Process[] myProcess = Process.GetProcessesByName("program name here");
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int SendMessageA(IntPtr hwnd, int wMsg, int wParam, uint lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetDlgItem(int hwnd, int childID);
public const int WM_LBUTTONDOWN = 0x0201;
public const int WM_LBUTTONUP = 0x0202;
public void SendClick()
{
IntPtr hwnd = myProcess[0].MainWindowHandle;
SetForegroundWindow(hwnd);
int intCID = 1389;
IntPtr ptrTest = GetDlgItem(hwnd, intCID);
SendKeys.SendWait(" ");
Thread.Sleep(1000);
SendKeys.SendWait("various text to be sent here");
Thread.Sleep(1000);
SendKeys.SendWait("{ENTER}");
Thread.Sleep(1000);
SendMessageA(ptrTest, WM_LBUTTONDOWN, WM_LBUTTONDOWN, 0);
}
I think you have to use the Win32 API to find the "receiving" application window, and then find a child window of that handle.
This is something I found googling Win32 API FindWindow
http://www.c-sharpcorner.com/UploadFile/shrijeetnair/win32api12062005005528AM/win32api.aspx