Desidero inviare l'input da tastiera a una finestra in un altro processo, senza portare quella finestra in primo piano. Posso usare PostMessage
per simulare il WM_KEYDOWN
e WM_KEYUP
; tutto quello che devo sapere è quale maniglia della finestra dovrebbe ricevere l'input da tastiera, ad esempio GetFocus, ma per un'altra applicazione non attiva.Chiamare GetGUIThreadInfo tramite P/Invoke
L'API GetGUIThreadInfo sembra promettente - restituisce un hwndFocus
per un'altra app. Ma non ho avuto fortuna a farlo funzionare da C# sul mio sistema operativo a 64 bit. Ho copiato (e poi ulteriormente ottimizzato) le dichiarazioni da pinvoke.net, ma tutto quello che riesco a recuperare è un codice di errore generico (maggiori dettagli di seguito).
Sto impostando cbSize prima chiamo GetGUIThreadInfo, quindi ho evitato il più ovvio potenziale problema.
Sto utilizzando Vista a 64 bit, quindi non so se il problema è che non sto usando l'API correttamente, o che funziona diversamente a 64-bit - Devo ancora trovare un esempio di codice che dice specificatamente che funziona correttamente con Win64.
Ecco il codice di esempio. Sto utilizzando GetWindowThreadProcessId as recommended, quindi non credo che il problema ha a che fare con la miscelazione ID filo con filo maniglie:
[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
è un handle di finestra valida; GetWindowThreadProcessId
restituisce un handle di thread diverso da zero. Ma la chiamata a GetGUIThreadInfo
restituisce sempre false
e il messaggio di eccezione è sempre "Il parametro non è corretto".
Nel caso in cui il problema era che GetGUIThreadInfo
in qualche modo non ha una versione a 64-bit, ho provato a cambiare tutte le 8 byte IntPtr
s nelle GuiThreadInfo
dichiarazione a 4 byte int
s, ma ho ancora avuto lo stesso errore.
Qualcuno ha un campione C# di lavoro di GetGUIThreadInfo
su Win64? Oppure esiste un altro modo per trovare quale sarebbe l'handle della finestra figlio focalizzata in un'altra app, senza rendere attiva quell'app?
Ouch. Hai ragione - non posso credere di averlo perso. Punto di galateo: questo risolveva il problema immediato, ma poi si presentava un altro problema; quindi il mio obiettivo finale di "maneggiare l'attenzione in altri processi" è ancora aperto. Dovrei modificare questa domanda o accettare questa risposta e scrivere una nuova domanda? –
In questo caso, la domanda riguarda davvero pInvocare GetGUIThreadInfo, quindi dovresti probabilmente votarlo come utile e contrassegnarlo come risposta. Potresti anche voler modificare il titolo per descrivere in modo più ristretto questa domanda. Quindi aggiungi una nuova domanda sul problema più generale che include cosa ... –
... il tuo requisito di base è e quello che hai provato fino ad ora. In generale, è necessario modificare una domanda per aggiungere informazioni o chiarezza per non modificare ciò che viene chiesto. –