问题
PROBLEM
This is my function to send key stroke in background.
class SendMessage
{
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
public static void sendKeystroke(string appName)
{
const int WM_KEYDOWN = 0x100;
IntPtr hWnd = FindWindow(null, appName);
IntPtr editx = FindWindowEx(hWnd, IntPtr.Zero, "edit", null);
PostMessage(editx, WM_KEYDOWN, (IntPtr)Keys.A, (IntPtr)0);
}
}
This code is work fine for notepad
for example let appName = "notepad".
However, I can manage to do it in other application ..I practice doing on LINE application.
As you can see in the picture lpszClass variable
= "edit" (small red circle) is for notepad.
I need to find it for LINE app so, I use WinSpy++
to capture those class name.
I found out that its class name is "ATL:00B53BE8" (big red circle) which I can type the message
in WinSpy++ and enter, it will appear to Line textbox (blue circle).
IN CONCLUSION
I try to replace capture class name with "edit" but no hope.
I don't understand why capture class name is not usable please help or give me some hint.
I don't know maybe it is about the hierarchy of system application different or not (pink one)
and I don't know which params in FindWindowEx mean that much.
My ultimate goal is to sent key stroke to other application without focus on them.
回答1:
You cannot expect WM_KEYDOWN
messages sent to applications that do not have the focus to have the desired effect. it is simply not supported. Receiving a WM_KEYDOWN
message implies, by the rules of Windows, that your application has the focus. Only focused applications can get keyboard input.
So what you are trying might work in certain cases, but it is not guaranteed to work. The application may make the quite-reasonable assumption that it has the focus if it is receiving keyboard input.
If it "works" in Notepad, it is because Notepad is a very dumb simple application. It is just an edit control with a menu bar. Its handling of the WM_KEYDOWN
message likely amounts to no more than adding the character represented by the key indicated by the message parameters to the edit control. Most other applications are more complicated. And even Notepad isn't guaranteed to work in all cases. For example, when its window is minimized. There are plenty of reports of problems like this elsewhere on this site and the Interwebz.
To put it simply: sending WM_KEYDOWN
and its friends are not the way that you simulate keyboard input in Windows. There are two basic ways of doing it. The first is to use the SendInput
function; the other is to install a WH_JOURNALPLAYBACK
hook. Both of these tacks have been variously taken by different versions of the implementation for the SendKeys
class in .NET. Both of them send the synthesized input to the focused window because, in Windows, that is the window that receives all input.
If this is to work at all, you absolutely must find another way of doing it. In the comments, David has suggested to use UI Automation, a tool designed for this purpose. It is conveniently wrapped by the .NET Framework. It is unclear why you are resisting this advice. With UI Automation, you can navigate easily through the hierarchy of windows in an application, using a nested tree structure. This tree is built automatically from all of the window handles in the process. This allows you to easily find the control(s) you want to manipulate. Then, you obtain the appropriate control patterns, and perform whatever action you want.
回答2:
From Discussion with David Herffernan
"You'd need multiple calls to walk through parent child hierarchy"
Now, I can make my code work.. However, it seem this isn't the right way to do (Hacking)
but, I want to answer this question for my reference
the key is use of FindWindowEx
it work as David Herffernan
said.
Instead of this..
public static void sendKeystroke(string appName)
{
const int WM_KEYDOWN = 0x100;
IntPtr hWnd = FindWindow(null, appName);
IntPtr editx = FindWindowEx(hWnd, IntPtr.Zero, "edit", null);
PostMessage(editx, WM_KEYDOWN, (IntPtr)Keys.A, (IntPtr)0);
}
I edit to this..
public static void sendKeystroke(string appName)
{
const int WM_KEYDOWN = 0x100;
IntPtr hWnd = FindWindow(null, appName);
IntPtr editx1 = FindWindowEx(hWnd, IntPtr.Zero, "SkinScrollWnd", null);
IntPtr editx2 = FindWindowEx(editx1, IntPtr.Zero, "SkinScrollMidWnd", null);
IntPtr editx3 = FindWindowEx(editx2, IntPtr.Zero, "ATL:00B53BE8", null);
PostMessage(editx3, WM_KEYDOWN, (IntPtr)Keys.A, (IntPtr)0);
}
来源:https://stackoverflow.com/questions/25718099/c-sharp-findwindowex-obtain-parameter-for-lpszclass-variable-by-winspy-not-wor