I'm working on a teamviewer-like application (need to move the cursor of an another pc and see the typing of my keyboard there). Is it possible to capture events from my (client) side ( MouseMove, MouseButtonDown, etc) and inject them directly to the other (server) side?
I want to know if exists WPF functions like these win32:
SendMessage();
PostMessage();
SendInput();
If not, how to send WPF Events using these??
Thanks in advance
You may hook your self up on these bubbling routed events, the true param there grabs all events even if they are handled, and even if they are inside child controls. So add them at the top of your visual hierarchy somewhere :)
WPF handlers
AddHandler(KeyUpEvent, new KeyEventHandler(OnKeyUp), true);
AddHandler(MouseUpEvent, new MouseButtonEventHandler(OnMouseUp), true);
private void OnMouseUp(Object sender, MouseButtonEventArgs e)
{
// Post/Send message, SendInput or whatever here..
}
private void OnKeyUp(Object sender, KeyEventArgs e)
{
// Post/Send message, SendInput or whatever here..
}
And yes you may use SendMessage, PostMessage and SendInput functions in WPF through interop.
Interop
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
internal static extern UINT SendInput(UINT nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);
Then you just inject your messages using interop. And yes it is also possible to hook your self onto a winproc in WPF. See this post for details.
pinvoke.net is a good source for w32 C# interop, but something tells me you are already aware of this :) You have an example of sending inputs here.
Hope it helps.
Related
I'm attempting to suppress some Windows keyboard shortcuts (e.g. ALT + TAB, LWIN/RWIN, ALT + F4) so my application can handle them elsehow (simulating keypresses on an external machine).
According to other SO questions and answers this is supposed to work:
this.PreviewKeyDown += (s, e) => {
if (e.Key == Key.LWin || e.Key == Key.RWin)
e.Handled = true;
};
Problem is, it doesn't work. Whenever I hit LWIN/RWIN, the Start menu still pops up which I want to suppress so my application alone can use it. In the above snippet, this refers to a WPF Window which was being focussed while testing this. (It should obviously only suppress the action once Window has focus.)
Any way to achieve what I'd like to achieve?
Thanks,
~Tgys
You can Hook all the Keyboard and even Mouse events to detect the source of input. In other words, if you use the Global Hook as mentioned in the link below, you can capture system events and either process them like normal events or suppress them.
You should have a look at this CodeProject article, Processing Global Mouse and Keyboard Hooks in C#
MSDN Reference:
A global hook monitors messages for all threads in the same desktop as the calling thread. A thread-specific hook monitors messages for only an individual thread. A global hook procedure can be called in the context of any application in the same desktop as the calling thread, so the procedure must be in a separate DLL module. A thread-specific hook procedure is called only in the context of the associated thread.
C# Code:
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public partial class MainWindow : Window
{
// Structure contain information about low-level keyboard input event
[StructLayout(LayoutKind.Sequential)]
private struct KBDLLHOOKSTRUCT
{
public Keys key;
public int scanCode;
public int flags;
public int time;
public IntPtr extra;
}
//System level functions to be used for hook and unhook keyboard input
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int id, LowLevelKeyboardProc callback, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hook);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hook, int nCode, IntPtr wp, IntPtr lp);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string name);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern short GetAsyncKeyState(Keys key);
//Declaring Global objects
private IntPtr ptrHook;
private LowLevelKeyboardProc objKeyboardProcess;
private IntPtr CaptureKey(int nCode, IntPtr wp, IntPtr lp)
{
if (nCode >= 0)
{
KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lp, typeof(KBDLLHOOKSTRUCT));
if (objKeyInfo.key == Keys.RWin || objKeyInfo.key == Keys.LWin) // Disabling Windows keys
{
return (IntPtr)1;
}
}
return CallNextHookEx(ptrHook, nCode, wp, lp);
}
public MainWindow()
{
InitializeComponent();
//Get Current Module
ProcessModule objCurrentModule = Process.GetCurrentProcess().MainModule;
//Assign callback function each time keyboard process
objKeyboardProcess = new LowLevelKeyboardProc(CaptureKey);
//Setting Hook of Keyboard Process for current module
ptrHook = SetWindowsHookEx(13, objKeyboardProcess, GetModuleHandle(objCurrentModule.ModuleName), 0);
}
}
Other Good References:
Low-level Windows API hooks from C# to stop unwanted keystrokes
Disable Special Keys in Win App C#
I want to send a window message from one application (console) to the wondow of another application. I can use WinAPI functions SendMessage or PostMessage, but may be there is managed way to do it?
There is no managed alternative to that but you can easily P/Invoke with:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
private void button1_Click(object sender, EventArgs e)
{
SendMessage(this.Handle, COMMAND_HERE, PARAM_HERE, 0);
}
i am trying to grab the selected text from the open form on a users machine. Currently i have tried using GetFocus which is defined as
'[DllImport("user32.dll")]
static extern int GetFocus();'
In the api it says - Retrieves the handle to the window that has the keyboard focus, if the window is attached to the calling thread's message queue. Which explains why my app can grab the selected text from a window thats part of my app, but not one thats external, like a pdf for example.
What alternative win32 method is available for me to use that would fit this purpose?
Thanks.
edit: this is the attempt at the moment
[DllImport("user32.dll")]
static extern int GetFocus();
[DllImport("user32.dll")]
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(int hWnd, int ProcessId);
[DllImport("user32.dll")]
static extern int GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern int SendMessage(int hWnd, int Msg, int wParam, StringBuilder lParam);
// second overload of SendMessage
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, uint Msg, out int wParam, out int lParam);
const int WM_SETTEXT = 12;
const int WM_GETTEXT = 13;
private static string PerformCopy()
{
try
{
//Wait 5 seconds to give us a chance to give focus to some edit window,
//notepad for example
System.Threading.Thread.Sleep(1000);
StringBuilder builder = new StringBuilder(500);
int foregroundWindowHandle = GetForegroundWindow();
uint remoteThreadId = GetWindowThreadProcessId(foregroundWindowHandle, 0);
uint currentThreadId = GetCurrentThreadId();
//AttachTrheadInput is needed so we can get the handle of a focused window in another app
AttachThreadInput(remoteThreadId, currentThreadId, true);
//Get the handle of a focused window
int focused = GetFocus();
//Now detach since we got the focused handle
AttachThreadInput(remoteThreadId, currentThreadId, false);
//Get the text from the active window into the stringbuilder
SendMessage(focused, WM_GETTEXT, builder.Capacity, builder);
return builder.ToString();
}
catch (System.Exception oException)
{
throw oException;
}
}
Check GetForegroundWindow.
I don't think you have much chance of succeeding with your current approach. I'm pretty sure there's no single general purpose API for getting hold of the current selection. I believe this because each application can implement text selection in its own way.
As an alternative solution you should consider using a clipboard listener. Listen for changes to the clipboard contents and whenever text is added you can suck it out of the clipboard and put it in your app's window.
I think this is a job for UI Automation (the API screen readers use). Here's a post that get's the selected text in C#.
I'm creating an application that uses a main project that is connected to several different DLLs. From one DLL window I need to be able to open a window in another but the DLL's can't reference each other.
It was suggested to me to use the sendmessage function in the first DLL and have a listener in the main program that directs that message to the appropriate DLL to open it's window.
However I'm not familiar at all with the sendmessage function and am having a lot of diffculty piecing things together from information I'm finding online.
If someone could please show me the correct way (if there is any) to use the sendmessage function and maybe how a listener captures that message that would be amazing. Here is some of the code I've got so far I'm not sure if I'm heading in the right direction.
[DllImport("user32.dll")]
public static extern int FindWindow(string lpClassName, String lpWindowName);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
public void button1_Click(object sender, EventArgs e)
{
int WindowToFind = FindWindow(null, "Form1");
}
public static extern int FindWindow(string lpClassName, String lpWindowName);
In order to find the window, you need the class name of the window. Here are some examples:
C#:
const string lpClassName = "Winamp v1.x";
IntPtr hwnd = FindWindow(lpClassName, null);
Example from a program that I made, written in VB:
hParent = FindWindow("TfrmMain", vbNullString)
In order to get the class name of a window, you'll need something called Win Spy
Once you have the handle of the window, you can send messages to it using the SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam) function.
hWnd, here, is the result of the FindWindow function. In the above examples, this will be hwnd and hParent. It tells the SendMessage function which window to send the message to.
The second parameter, wMsg, is a constant that signifies the TYPE of message that you are sending. The message might be a keystroke (e.g. send "the enter key" or "the space bar" to a window), but it might also be a command to close the window (WM_CLOSE), a command to alter the window (hide it, show it, minimize it, alter its title, etc.), a request for information within the window (getting the title, getting text within a text box, etc.), and so on. Some common examples include the following:
Public Const WM_CHAR = &H102
Public Const WM_SETTEXT = &HC
Public Const WM_KEYDOWN = &H100
Public Const WM_KEYUP = &H101
Public Const WM_LBUTTONDOWN = &H201
Public Const WM_LBUTTONUP = &H202
Public Const WM_CLOSE = &H10
Public Const WM_COMMAND = &H111
Public Const WM_CLEAR = &H303
Public Const WM_DESTROY = &H2
Public Const WM_GETTEXT = &HD
Public Const WM_GETTEXTLENGTH = &HE
Public Const WM_LBUTTONDBLCLK = &H203
These can be found with an API viewer (or a simple text editor, such as notepad) by opening (Microsoft Visual Studio Directory)/Common/Tools/WINAPI/winapi32.txt.
The next two parameters are certain details, if they are necessary. In terms of pressing certain keys, they will specify exactly which specific key is to be pressed.
C# example, setting the text of windowHandle with WM_SETTEXT:
x = SendMessage(windowHandle, WM_SETTEXT, new IntPtr(0), m_strURL);
More examples from a program that I made, written in VB, setting a program's icon (ICON_BIG is a constant which can be found in winapi32.txt):
Call SendMessage(hParent, WM_SETICON, ICON_BIG, ByVal hIcon)
Another example from VB, pressing the space key (VK_SPACE is a constant which can be found in winapi32.txt):
Call SendMessage(button%, WM_KEYDOWN, VK_SPACE, 0)
Call SendMessage(button%, WM_KEYUP, VK_SPACE, 0)
VB sending a button click (a left button down, and then up):
Call SendMessage(button%, WM_LBUTTONDOWN, 0, 0&)
Call SendMessage(button%, WM_LBUTTONUP, 0, 0&)
No idea how to set up the listener within a .DLL, but these examples should help in understanding how to send the message.
You are almost there. (note change in the return value of FindWindow declaration). I'd recommend using RegisterWindowMessage in this case so you don't have to worry about the ins and outs of WM_USER.
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, String lpWindowName);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
public void button1_Click(object sender, EventArgs e)
{
// this would likely go in a constructor because you only need to call it
// once per process to get the id - multiple calls in the same instance
// of a windows session return the same value for a given string
uint id = RegisterWindowMessage("MyUniqueMessageIdentifier");
IntPtr WindowToFind = FindWindow(null, "Form1");
Debug.Assert(WindowToFind != IntPtr.Zero);
SendMessage(WindowToFind, id, IntPtr.Zero, IntPtr.Zero);
}
And then in your Form1 class:
class Form1 : Form
{
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
private uint _messageId = RegisterWindowMessage("MyUniqueMessageIdentifier");
protected override void WndProc(ref Message m)
{
if (m.Msg == _messageId)
{
// do stuff
}
base.WndProc(ref m);
}
}
Bear in mind I haven't compiled any of the above so some tweaking may be necessary.
Also bear in mind that other answers warning you away from SendMessage are spot on. It's not the preferred way of inter module communication nowadays and genrally speaking overriding the WndProc and using SendMessage/PostMessage implies a good understanding of how the Win32 message infrastructure works.
But if you want/need to go this route I think the above will get you going in the right direction.
You don't need to send messages.
Add an event to the one form and an event handler to the other. Then you can use a third project which references the other two to attach the event handler to the event. The two DLLs don't need to reference each other for this to work.
It doesn't sound like a good idea to use send message. I think you should try to work around the problem that the DLLs can't reference each other...
Some other options:
Common Assembly
Create another assembly that has some common interfaces that can be implemented by the assemblies.
Reflection
This has all sorts of warnings and drawbacks, but you could use reflection to instantiate / communicate with the forms. This is both slow and runtime dynamic (no static checking of this code at compile time).
Building on Mark Byers's answer.
The 3rd project could be a WCF project, hosted as a Windows Service. If all programs listened to that service, one application could call the service. The service passes the message on to all listening clients and they can perform an action if suitable.
Good WCF videos here - http://msdn.microsoft.com/en-us/netframework/dd728059
I'm trying to scroll a textbox using the form's WndProc method. The code I've come up with so far, after scouring the internet, looks like this:
private void ScrollTextBox()
{
scrollMessage = Message.Create(TabContents.Handle, 0x00B6, new IntPtr(0x0003), new IntPtr(0x0000));
this.WndProc(ref scrollMessage);
}
where TabContents is a TextBox.
For some reason, nothing happens when i call this method. I'd like to know why. I realise that i can accomplish the same with the MoveToCaret method, but I'm curious why this is not working.
EDIT:
As in the posted answer from Beaner, I wrote another method using SendMessage:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
private void ScrollTextBox2(int lines)
{
SendMessage(TabContents.Handle, 0x00B6, new IntPtr(0), new IntPtr(lines));
}
This seems to work %100. I'm still curious why this.WndProc(ref message) doesn't work, given a message created with the same set of parameters.
This may be possible, but I have never tried it that way. I have used SendMessage to send a windows message directly to the textbox to cause scrolling.
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(TabContents.Handle, WM_VSCROLL, (IntPtr) SB_BOTTOM, IntPtr.Zero);