Я хочу отправить ввод с клавиатуры в окно другого процесса, не выводя это окно на передний план. Я могу использовать PostMessage
для подделки WM_KEYDOWN
и WM_KEYUP
; все, что мне нужно знать, это то, какой дескриптор окна должен получать ввод с клавиатуры - то есть что-то вроде GetFocus , но для другого неактивного приложения.
API GetGUIThreadInfo выглядит многообещающе - он возвращает hwndFocus
для другого приложения. Но мне не повезло заставить его работать из C # на моей 64-битной ОС. Я скопировал (а затем и далее подправил) объявления из pinvoke.net , но все, что я когда-либо получаю, - это общий код ошибки (более подробно ниже).
Я устанавливаю cbSize перед вызовом GetGUIThreadInfo, поэтому я избежал наиболее очевидной потенциальной проблемы.
Я использую 64-битную Vista, поэтому я не знаю, в чем проблема: я неправильно использую API или что он работает по-другому в 64-битной системе - мне еще не удалось найти код пример, который конкретно говорит, что он успешно работает в Win64.
Вот пример кода. Я использую GetWindowThreadProcessId как рекомендовано , поэтому я не думаю, что проблема связана с смешением идентификаторов потоков с дескрипторами потоков:
[StructLayout(LayoutKind.Sequential)]
internal struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[StructLayout(LayoutKind.Sequential)]
internal class GuiThreadInfo
{
public int cbSize;
public uint flags;
public IntPtr hwndActive;
public IntPtr hwndFocus;
public IntPtr hwndCapture;
public IntPtr hwndMenuOwner;
public IntPtr hwndMoveSize;
public IntPtr hwndCaret;
public Rect rcCaret;
}
[DllImport("user32.dll")]
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool GetGUIThreadInfo(uint idThread, ref GuiThreadInfo lpgui);
IntPtr GetFocusedHandleFromProcessWithWindow(IntPtr window)
{
var threadId = GetWindowThreadProcessId(window, IntPtr.Zero);
var info = new GuiThreadInfo();
info.cbSize = Marshal.SizeOf(info);
if (!GetGUIThreadInfo(threadId, ref info))
throw new Win32Exception();
return info.hwndFocus;
}
window
- допустимый дескриптор окна; GetWindowThreadProcessId
возвращает ненулевой дескриптор потока. Но вызов GetGUIThreadInfo
всегда возвращает false
, и сообщение об исключении всегда "Параметр неверен".
На всякий случай проблема была в том, что GetGUIThreadInfo
почему-то не имеет 64-битной версии, я попытался изменить все 8-байтовые IntPtr
с в объявлении GuiThreadInfo
на 4-байтовые int
с , но я все еще получил ту же ошибку.
У кого-нибудь есть рабочий образец C # GetGUIThreadInfo
на Win64? Или есть другой способ узнать, какой дескриптор сфокусированного дочернего окна будет в другом приложении, не делая его активным?