Autor
|
Tema: Manipular ventana en segundo plano (Leído 4,981 veces)
|
rigorvzla
Desconectado
Mensajes: 221
|
hola amigos en este codigo, puedo enviar una orden a un proceso, el detalle esta en que me trae al frente ese proceso, y necesito que mande la orden pero deje la ventana en segundo plano o no ponerla como ventana activa [DllImport("User32.dll")] static extern int SetForegroundWindow(IntPtr point);
Process p = (Process)listBox.SelectedItem; if (p != null) { IntPtr h = p.MainWindowHandle; SetForegroundWindow(h); simuladorTeclas.Keyboard.KeyPress(VirtualKeyCode.VK_A); } con ese codigo, envio una pulsacion de tecla a la ventana selecionada en el listbox, y en efecto funciona, el detalle es que trae al frente la ventana de ese proceso, mi idea es que se mantenga en segundo plano y no se convierta en principal o ventana activa.
|
|
|
En línea
|
|
|
|
|
rigorvzla
Desconectado
Mensajes: 221
|
Hola Elektro en efecto uso este nugget https://github.com/michaelnoonan/inputsimulatormuy practico y bueno, lo muestro en el codigo que deje anteriormente, mi no saber es como enviar por medio de ese nugget una pulsacion de tecla a una ventana NO activa, en el codigo anterior selecciono el proceso desde un listbox y envia la pulsacion a esa ventana (ejemplo notepad) todo va bien , lo malo es que la trae al frente o la vuelve activa y no quiero eso. eh revisado este post que me dejaste https://foro.elhacker.net/net/autologin_en_otra_aplicacion_c-t489446.0.html;msg2178786#msg2178786De lo contrario, lo recomendable, y dado que el propósito sería evitar depender de que la ventana tenga activo el foco de entrada, sería utilizar la función nativa SendMessage (o PostMessage, según cómo lo quieras hacer) junto al mensaje de ventana WM_SETTEXT, logicamente antes de poder enviar el mensaje primero debes identificar la ventana (el control) al que le quieres enviar el mensaje (el texto a insertar). De nuevo no hace falta mencionar que tienes ejemplos (miles de ellos) en la WWW. Y si necesita enviar cualquier otra cosa que no sea texto, es decir, si lo que quieres es simular una tecla o una combinación de teclas, entonces debes usar el mensaje de ventana WM_KEYDOWN + WM_KEYUP (quizás también WM_SYSKEYDOWN + WM_SYSKEYDOWN, dependiendo de las teclas específicas que necesites simular). Repito, esta metodología no requiere tener activo el foco de entrada de la ventana objetivo. esta parte no lo entendi muy bien, ya que no se usar mucho el Sendkey por eso me decidi con el inputsimulator. En resumen, es posible enviar la accion a una ventana no activa una pulsacion de tecla con el inputSimulator? de ser afirmativo, como? de lo contrario, como puedo lograr mi objetivo con el sendkey.
|
|
|
En línea
|
|
|
|
Eleкtro
Ex-Staff
Desconectado
Mensajes: 9.885
|
mi no saber es como enviar por medio de ese nugget una pulsacion de tecla a una ventana NO activa No puedes. En resumen, es posible enviar la accion a una ventana no activa una pulsacion de tecla con el inputSimulator? No. La librería Windows Input Simulator es un wrapper de la función nativa SendInput, y el propósito de dicha función es simular las pulsaciones de teclado, movimientos del mouse o pulsaciones de los botones a la ventana que tenga el foco de entrada activo. Así pues, ni con SendInput ni con System.Windows.Forms.SendKeys.Send puedes hacer tal cosa, ya que ambos requieren que primero actives el foco de la ventana a la que pretendes enviarle las pulsaciones (función nativa AttachThreadInput + SetFocus, o SetForegroundWindow), lo cual activará dicha ventana. Creo que todo lo que acabo de explicar ya lo expliqué en el comentario que te sugerí leer. El propósito era evitar la necesidad de volver a explicar lo mismo... de lo contrario, como puedo lograr mi objetivo con el sendkey. Como ya recomendé en el párrafo que has citado, deberías utilizar las funciones de mensajería de ventana. La más simple para este caso es la función PostMessage, ya que si deseas simular una pulsación del teclado usando la función SendMessage / SendMessageTimeout entonces deberás construir un "parámetro de tecla" más complejo (el cómo construirlo está especificado en la documentación del mensaje de ventana WM_KEYDOWN y WM_KEYUP en docs.microsoft.com / MSDN). Un ejemplo básico: Friend NotInheritable Class NativeMethods Private Sub New() End Sub <DllImport("User32.dll", SetLastError:=True)> Friend Shared Function PostMessage( <MarshalAs(UnmanagedType.SysInt)> hWnd As IntPtr, <MarshalAs(UnmanagedType.U4)> msg As Integer, <MarshalAs(UnmanagedType.SysInt)> wParam As IntPtr, <MarshalAs(UnmanagedType.SysInt)> lParam As IntPtr ) As <MarshalAs(UnmanagedType.Bool)> Boolean End Function End Class
... Public Shared Function SendKeyDown(ByVal hWnd As IntPtr, ByVal key As Integer) As Boolean Const WM_KEYDOWN As Integer = 256 Return NativeMethods.PostMessage(hWnd, WM_KEYDOWN, New IntPtr(key), IntPtr.Zero) End Function Public Shared Function SendKeyUp(ByVal hWnd As IntPtr, ByVal key As Integer) As Boolean Const WM_KEYUP As Integer = 257 Return NativeMethods.PostMessage(hWnd, WM_KEYUP, New IntPtr(key), IntPtr.Zero) End Function Public Shared Function SendKeyPress(ByVal hWnd As IntPtr, ByVal key As Integer) As Boolean Return ((SendKeyDown(hWnd, key) And SendKeyUp(hWnd, key)) = True) End Function
... Dim hWnd As IntPtr = Process.GetProcessesByName("notepad").Single().MainWindowHandle Dim key As Integer = System.Windows.Forms.Keys.F5 ' VK_F5 (0x74) Dim success As Boolean = SendKeyPress(hWnd, key) If Not (success) Then Dim win32ErrCode As Integer = Marshal.GetLastWin32Error() Throw New Win32Exception(win32ErrCode) End If
Saludos.
|
|
« Última modificación: 7 Enero 2019, 20:39 pm por Eleкtro (sin pilas) »
|
En línea
|
|
|
|
rigorvzla
Desconectado
Mensajes: 221
|
gracis hombre!! es lo maximo y ademas busque informacion extra por que lei uno de tus post donde mucha MUCHISIMA infomracion existe en ingles solo que hay que saber poner las palabras correctas jeje ahi te eh citado . agradezdo de tu ayuda. como un extra , como podria obtener el nombre de un proceso seleccionado desde un listbox?
string = text "System.Diagnostics.Process (conhost)" no me funciona sale el nombre completo de toda la using y entre parentecis el proceso jeje
|
|
« Última modificación: 8 Enero 2019, 18:46 pm por rigorvzla »
|
En línea
|
|
|
|
Eleкtro
Ex-Staff
Desconectado
Mensajes: 9.885
|
como podria obtener el nombre de un proceso seleccionado desde un listbox? Si solo conoces el nombre del proceso entonces debes usar la función Process.GetProcessesByName() (como en el ejemplo que te mostré.). Dicha función devolverá un Array, puesto que puede haber más de un proceso en ejecución con el mismo nombre, por ende, debes utilizar algún criterio adicional para elegir un único proceso del Array. Lo ideal es que te asegures de conocer el identificador de proceso (PID), ya que dicho identificador es único, y de esa manera puedes usar la función Process.GetProcessById() para devolver un único proceso / elemento... un ejemplo: VB.NET: Dim prDict As New SortedDictionary(Of String, Integer)( Process.GetProcesses().ToDictionary(Function(pr) String.Format("{0} [{1}]", pr.ProcessName, pr.Id), Function(pr) pr.Id), StringComparer.Ordinal) Me.ListBox1.DataSource = prDict.Keys.ToList()
... Private Sub ListBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) Dim lb As ListBox = DirectCast(sender, ListBox) Dim pid As Integer = prDict(lb.SelectedItem.ToString()) Dim pr As Process = Process.GetProcessById(pid) ' ... End Sub
C#: SortedDictionary<string, int> prDict = new SortedDictionary <string, int>(Process .GetProcesses().ToDictionary( (pr) => string.Format("{0} [{1}]", pr.ProcessName, pr.Id), (pr) => pr.Id), StringComparer.Ordinal); this.listBox1.DataSource = prDict.Keys.ToList();
... private void listBox1_SelectedIndexChanged(object sender, EventArgs e) { ListBox lb = (ListBox)sender; int pid = prDict[lb.SelectedItem.ToString()]; Process pr = Process.GetProcessById(pid); // ... }
Nótese que este ejemplo tan solo tiene el objetivo de demostrarte como solucionar el problema que has descrito. No se tiene en cuenta si un proceso sigue en ejecución o se terminó despues de haber seleccionado el nombre de dicho proceso en el ListBox; para ello siempre puedes utilizar una colección que implemente la interfaz INotifyCollectionChanged (ej. ObservableCollection) y refrescar la lista de procesos en ejecución del ListBox mediante una tasa de refresco a tu elección... Saludos
|
|
« Última modificación: 9 Enero 2019, 06:15 am por Eleкtro (sin pilas) »
|
En línea
|
|
|
|
rigorvzla
Desconectado
Mensajes: 221
|
muchisimas gracias, has respondido 2 preguntas mas de un golpe como lo que era, que me de la lista de manera ordenada y la obtencion del id del proceso, grande pues!!! jeje. Yo lo que hice para poder obtener lo que queria fue, extraer el proceso de los parentesis con un split jeje y asunto resuelto. string = text "System.Diagnostics.Process (Proceso)" de todos modos, gracias nuevamente ya que por estetica habia quedado cutre, y con tu explicacion podre hacerlo de una manera elegante y con mas detalle, ordenada y con el Id en caso de ser necesario mas adelante nuevamente gracias!! Graciasa tambien por la ayuda de el metodo e segundo plano tambien lo resolvi de la siguiente manera asi como estan en tus codigos de ejemplo, solo que lo aplique a C# [DllImport("user32.dll")] static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam); const UInt32 WM_KEYDOWN = 0x0100; const UInt32 WM_KEYUP = 0x0101;
[STAThread] public static void accionTecla(int tecla, string proceso) { Process[] processes = Process.GetProcessesByName(proceso); foreach (Process proc in processes) { PostMessage(proc.MainWindowHandle, WM_KEYDOWN, tecla, 0); PostMessage(proc.MainWindowHandle, WM_KEYUP, tecla, 0); } } Sirvio de lo lindo, mas no se, por que en un textbox si digo que precione "a" me la preciona 2 veces... asumo por ambos WM_KEY pero probe con solo el down y hay aplicaciones que deja la tecla marcada y no la suelta, cuando puse el up , walla!! asunto resuelto, y apesar que no me ha dado problemas , me gustaria saber si puedo solo mostrar unasola pulsasion de letra "a" . Aparte pero del mismo tema, busque hacer combinaciones como "ctrl + 1" y se volvia loco apretando unos muuuuchas veces use el sentido comun pero.... como q falta algo mas jeje PostMessage(proc.MainWindowHandle, WM_KEYDOWN, tecla1, 0); PostMessage(proc.MainWindowHandle, WM_KEYDOWN, tecla2, 0); PostMessage(proc.MainWindowHandle, WM_KEYUP, tecla2, 0); PostMessage(proc.MainWindowHandle, WM_KEYUP, tecla1, 0);
Este ultimo codigo es referencial pero asi lo aplique bien hecho y pasa lo que mensione.
|
|
« Última modificación: 9 Enero 2019, 18:29 pm por rigorvzla »
|
En línea
|
|
|
|
Eleкtro
Ex-Staff
Desconectado
Mensajes: 9.885
|
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam); La firma de esa función debe ser portable, como en el ejemplo que te mostré. Me pregunto por que en lugar de convertir (usando cualquier convertidor de código online) y copiar el código que te mostré, copiaste un código aleatorio de Internet... Simplemente reemplaza el valor int de los parámetros lParam y wParam, por IntPtr, tal que así: internal sealed class NativeMethods { private NativeMethods() {} [DllImport("User32.dll", SetLastError=true)] [return: MarshalAs(UnmanagedType.Bool)] internal extern static bool PostMessage([MarshalAs(UnmanagedType.SysInt)] IntPtr hWnd, [MarshalAs(UnmanagedType.U4)] uint msg, [MarshalAs(UnmanagedType.SysInt)] IntPtr wParam, [MarshalAs(UnmanagedType.SysInt)] IntPtr lParam); }
probe con solo el down y hay aplicaciones que deja la tecla marcada y no la suelta, cuando puse el up , walla!! asunto resuelto Los nombres de los mensajes de ventana son auto-descriptivos, WM_KEYDOWN = presionar tecla, WM_KEYUP = soltar tecla. Logicamente hasta que no envies el mensaje WM_KEYUP, la tecla seguirá virtuálmente presionada.
me gustaria saber si puedo solo mostrar unasola pulsasion de letra "a" .
Primero debes enviar el mensaje WM_KEYDOWN para presionar la tecla, y luego WM_KEYUP para soltarla. Así es como funciona, no le busques atajos.
busque hacer combinaciones como "ctrl + 1" y se volvia loco En teoría no se puede simular la pulsación de modificadores de tecla o teclas extendidas mediante SendMessgae / PostMessage. Me apoyo en la opinión de gurús de la programación y de .NET como el señor Hans Passant: https://stackoverflow.com/a/5145435/1248295. Aunque en realidad si que hay formas de hacerlo con PostMessage, pero para casos específicos en los que sabes exactamente que parámetros (lParam y wParam) debes enviar despues de haber analizado a fondo como se envían los mensajes de ventana en la aplicación. En fin. Para simular la pulsación de teclas "especiales" como ALT, CONTROL o SHIFT izquierdo y derecho, siempre puedes utilizar la función keybd_event para modificar el estado de una tecla (estado presionado, o no presionado) de forma global, pues no se puede modificar el estado de dichas teclas solamente para una ventana en específico... Al código que ya tienes, le añadirías esto: [DllImport("user32.dll", EntryPoint="keybd_event", SetLastError=true)] internal extern static void KeybdEvent([MarshalAs(UnmanagedType.U1)] byte vkey, [MarshalAs(UnmanagedType.U1)] byte scanCode, [MarshalAs(UnmanagedType.U4)] KeybdEventFlags flags, [MarshalAs(UnmanagedType.SysUInt)] UIntPtr extraInfo); [DllImport("user32.dll", SetLastError=true)] [return: MarshalAs(UnmanagedType.U4)] internal extern static uint MapVirtualKey([MarshalAs(UnmanagedType.U4)] uint code, [MarshalAs(UnmanagedType.U4)] MapVirtualKeyMapTypes mapType);
... [Flags] internal enum KeybdEventFlags: uint { NonExtendedKey = 0x0, ExtendedKey = 0x1, KeyUp = 0x2 } internal enum MapVirtualKeyMapTypes: uint { VKeyToScanCode = 0x0, ScanCodeToVkey = 0x1, VKeyToChar = 0x2, ScanCodeToVKeyExtended = 0x3, VKeyToScanCodeExtended = 0x4 }
... Entonces, así puedes hacer para presionar por ejemplo la combinación de teclas CONTROL+S a una ventana no activa, en este ejemplo Notepad: Dim hWnd As IntPtr = Process.GetProcessesByName("notepad").Single().MainWindowHandle Dim modKey As Byte = CByte(Keys.LControlKey) Dim scanCode As Byte = CByte(NativeMethods.MapVirtualKey(modKey, MapVirtualKeyMapTypes.VKeyToScanCode)) ' Presionar modificador de tecla NativeMethods.KeybdEvent(modKey, scanCode, KeybdEventFlags.NonExtendedKey, UIntPtr.Zero) ' Presionar la tecla "S" SendKeyPress(hWnd, Keys.S) Thread.Sleep(100) ' Intervalo necesario ya que PostMessage es asincrónico. ' Soltar modificador de tecla NativeMethods.KeybdEvent(modKey, scanCode, KeybdEventFlags.NonExtendedKey Or KeybdEventFlags.KeyUp, UIntPtr.Zero)
PostMessage(proc.MainWindowHandle, WM_KEYDOWN, tecla1, 0); PostMessage(proc.MainWindowHandle, WM_KEYDOWN, tecla2, 0); PostMessage(proc.MainWindowHandle, WM_KEYUP, tecla2, 0); PostMessage(proc.MainWindowHandle, WM_KEYUP, tecla1, 0);
Eso estaría bien siempre y cuando 'tecla1' o 'tecla2' no sean modificadores de tecla (CTRL, ALT, SHIFT), y además siempre que entre llamada y llamada añadas un intervalo de espera de digamos 100 ms para evitar una posible desincronización de los eventos del teclado, pues como ya dije más arriba PostMessage es una función asincrónica. Saludos.
|
|
« Última modificación: 9 Enero 2019, 23:50 pm por Eleкtro (sin pilas) »
|
En línea
|
|
|
|
rigorvzla
Desconectado
Mensajes: 221
|
Genial, me has aclarado grandes dudas, muchas gracias, y disculpo lo del codigo solo que hay cosas que aun se me dificultan de leer (codigo) para pasar a C# , de todos modos esto seguramente lo consultare mas adelante cuando mis conocimientos sean un poco mayores, entendi lo de las teclas especiales y es algo que dejare para mas adelante!! jeje , pocierto gracias nuevamente por el ListBox quedo todo , nene jejeje
|
|
|
En línea
|
|
|
|
Eleкtro
Ex-Staff
Desconectado
Mensajes: 9.885
|
disculpo lo del codigo solo que hay cosas que aun se me dificultan de leer (codigo) para pasar a C# No hay nada que disculpar, supongo que es comprensible, yo te lo puse en VB.NET esperando que pusieras de tu parte y lo convirtieses a C# por que no me gusta darlo todo hecho y regalado, pero claro, tampoco estás obligado a convertir nada. xD Saludos.
|
|
|
En línea
|
|
|
|
|
Mensajes similares |
|
Asunto |
Iniciado por |
Respuestas |
Vistas |
Último mensaje |
|
|
Ficheros .bat en Segundo Plano?¿
« 1 2 »
Hacking
|
yisas_fight
|
14
|
38,746
|
8 Septiembre 2011, 09:36 am
por WHK
|
|
|
exec en segundo plano
PHP
|
sexto
|
0
|
2,070
|
11 Septiembre 2012, 13:02 pm
por sexto
|
|
|
segundo plano
Windows
|
makinavaja3500
|
2
|
3,184
|
6 Diciembre 2012, 21:32 pm
por makinavaja3500
|
|
|
Consulta Coordenadas de Ventana en segundo plano
.NET (C#, VB.NET, ASP)
|
rigorvzla
|
4
|
3,211
|
19 Marzo 2019, 00:26 am
por rigorvzla
|
|