PDA

Ver la Versión Completa : Manipular aplicación externa


oabel5
23-05-2010, 09:11:15
Hola,
yo no programo en Delphi (lo hago en C) sin embargo me atreví a hacer una consulta en este foro, porque lamentablemente en los foros de C no encontré solución a mi problema. Ademas me dí cuenta que en este Foro tienen mucho mas material acerca de la problematica que voy a plantear.
Desde ya les agradezco a todos por su atención y por toda respuesta que me puedan dar .
Uso el LabWindows, en el que puedo programar en C, pero no en C++.
Necesito escribir un programa, el cual me abra otro y desde mi programa poder manipular a ese otro. Un ejemplo mas claro:
Mi programa arranca, abre el NotePad.exe; desde mi programa le indico que vaya a "File" y abra la opción "Abrir". Hice lo siguiente:

HWND wnd;
PROCESS_INFORMATION pi = {0};
STARTUPINFO si = {sizeof(si)};

CreateProcess(NULL, "notepad.exe", NULL, NULL, FALSE, 0, NULL,NULL, &si, &pi);
wnd = FindWindow (NULL,"Unbenannt - Editor"); //encuentra la nueva ventana
PostMessage(wnd, WM_COMMAND,HIWORD(1)+2,0);//Con esto abro la ventana "Abrir" del NotePad
wnd = FindWindowEx(wnd,0,"Edit",NULL);
for( i= 1;i<= 10;i++)
SendMessage(wnd, WM_CHAR, 48 , 0); //escribe en NotePad diez veces "0"


Mi pregunta es, cómo logro abrir la ventana "Abrir" indicandole desde mi programa que se simule apretar las teclas: Ctrl + 'O', mas o menos había pensado en esto:
PostMessage(wnd, WM_KEYDOWN, VK_CONTROL+'O', 0);
pero no funciona, porque el tercer parámetro de PostMessage solo acepta una constante; intente enviar dos PostMessage:

PostMessage(wnd, WM_KEYDOWN, VK_CONTROL, 0);
PostMessage(wnd, WM_KEYDOWN, VK_O, 0); // VK_O=0x4F

pero tampoco funciona.
Talvez se preguntan, porque quiero abrir de otra forma la ventana "Abrir", el problema es que desde mi programa tengo que manipular otro programa que no es el NotePad, osea en ese otro programa no funciona el:
PostMessage(wnd, WM_COMMAND,HIWORD(1)+2,0);
espero puedan ayudarme con este problema, porque despues de eso tengo otras preguntas referidos al caso, de por ejemplo: una vez abierto la ventana "Abrir", cómo puedo incluir una ruta en el espacio donde se pone el nombre del archivo a abrirse, por ejemplo quiero poner ahi: C:\TEST\test.txt
Gracias nuevamente por toda respuesta. Abel

LoPiTaL
23-05-2010, 15:00:12
Sin tener gran idea de cómo funcionan exactamente los mensajes en Windows, diría que para detectar algo del estilo Ctrl+XXXX debes mandar el evento KeyDown del Ctrl, seguido del KeyDown y KeyUp de la tecla en cuestión.
Es decir, debes hacer keydown del ctrl y KeyPress de la tecla que toque (no sé si realmente existe el evento KeyPress o si se simula lanzando los dos que he citado anteriormente, el KeyDown y el KeyUp).
Para terminar la simulación completa de las pulsaciones del teclado, deberías lanzar el KeyUp del ctrl después de los de la tecla en cuestión.

Si alguien más experimentado que yo puede confirmarlo, se agradecería.

Un saludo,
LoPiTaL

oabel5
23-05-2010, 15:08:53
Hola LoPiTal,
gracias por la respuesta, pero lamentablemente la idea que tienes ya la realicé y asi tampoco funciona.
Saludos.
Abel.

escafandra
24-05-2010, 08:21:22
Porqué no arrancar el notepad pasándole como parámetro el archivo que quieres abrir. Por otro lado puedes consultar esto (http://clubdelphi.com/foros/showpost.php?p=361975&postcount=7)

Saludos.

escafandra
24-05-2010, 09:22:56
Sui lo prefieres en C:
Keyb_Event(char C)
{
WORD S = VkKeyScan(C);
if(S & 0x0100) keybd_event(VK_SHIFT,0,0,0);
if(S & 0x0200) keybd_event(VK_LCONTROL,0,0,0);
if(S & 0x0400) keybd_event(VK_LMENU,0,0,0);

keybd_event(S,0,0,0);
keybd_event(S,0,KEYEVENTF_KEYUP,0);

if(S & 0x0100) keybd_event(VK_SHIFT,0,KEYEVENTF_KEYUP,0);
if(S & 0x0200) keybd_event(VK_LCONTROL,0,KEYEVENTF_KEYUP,0);
if(S & 0x0400) keybd_event(VK_LMENU,0,KEYEVENTF_KEYUP,0);

}

:D
Saludos.

LoPiTaL
24-05-2010, 15:52:26
Tengo que decir que a mí sí que me ha funcionado tu código correctamente, salvo lo del CreateProcess que me daba error y el FindWindow, que he tenido que cambiarle el nombre de la ventana.

He abierto el bloc de notas a parte, y desde Delphi he ejecutado:


wnd := FindWindow (nil,'Sin título - Bloc de notas'); //encuentra la nueva ventana
if wnd=0 then begin
showmessage('Block de notas no abierto.');
Exit;
end;
PostMessage(wnd, WM_COMMAND,HIWORD(1)+2,0);//Con esto abro la ventana "Abrir" del NotePad
PostMessage(wnd, WM_KEYDOWN, VK_CONTROL, 0);
PostMessage(wnd, WM_KEYDOWN, $4F, 0); // VK_O=0x4F


y me ha abierto la ventana "Abrir" en el bloc de notas. Comprueba que tras el FindWindow wnd es distinto de 0, que con lo que tú habías puesto a mí me salía 0 y por eso los PostMessage parece que no hagan nada.
La de CreateProcess no me funcionaba porque no he inicializado si y pi, y la verdad no sabía cómo hacerlo :cool:

Ya comentas algo.

Un saludo,
LoPiTaL

oabel5
24-05-2010, 18:42:59
Hola escafandra,
gracias por la respuesta a mis preguntas.
Como indiqué, mi objetivo es escribir un programa, desde el cual llamar a otra aplicación y desde mi programa manipular esa otra aplicación.
Con el keybd_event(...) no puedo solucionar este problema, ya que de alguna forma tengo que indicar a mi programa el Handle de lo ventana de la otra aplicación y eso no me imagino como hacerlo con el keybd_event(...).
Lo que talvez no me expliqué bien, es que en realidad el programa que estoy escribiendo tiene que llamar a otra aplicación que no es el NotePad.exe. Solamente era un ejemplo eso lo del NotePad, para que me entiendan mejor. Como indiqué a la final mi programa no solo tiene que abrir un archivo en la otra aplicación, sinó tiene que hacer otras rutinas mas, por ejemplo presionar algunos botones cuando este lo pide.

Hola LoPiTal,
a ti tambien te agradezco por tu respuesta. El código que escribí tambien corrió en mi PC, solo que yo tengo el Windows XP en alemán, por eso a mi me salía:
FindWindow (nil,'Unbenannt - Editor');
el problema consiste en que yo no quiero abrir la ventana "Abrir" de esta forma:
PostMessage(wnd, WM_COMMAND,HIWORD(1)+2,0);//
lo quiero abrir simulando presionar las teclas: Ctrl + 'o'.
Como indico nuevamente, la otra aplicación que quiero manipular desde mi programa, no es el NotePad (ese solo era un ejemplo). En esta otra aplicación la ventana "Abrir" reacciona cuando se presiona esas dos teclas: Ctrl + 'o', mi problema consiste en que no sé como enviar un mensaje haciendo esa combinación de teclas.
Saludos.
Abel

Chris
24-05-2010, 18:50:35
Hola,

Alguna vez has probado con hooks (http://en.wikipedia.org/wiki/Hooking)?

Puedes investigar sobre el tema y ver si te funciona. Son muy poderosos cuando los sabes utilizar.

Saludos

escafandra
24-05-2010, 19:14:12
La función que propongo simula cualquier pulsación en el teclado, sólo tienes que tener el foco en la ventana que quieras que reciba las pulsaciones. FindWindow te devuelve el Handle de la ventana que buscas, pues lo usas luego con SetFocus para darle el foco y ya lo tienes.

Saludos.

LoPiTaL
24-05-2010, 20:18:23
Es verdad! Que al probar copié también la instrucción
PostMessage(wnd, WM_COMMAND,HIWORD(1)+2,0);//Con esto abro la ventana "Abrir" del NotePad

:o

Lo siento, jejeje se me pasó. Voy a seguir probando, que me ha dado curiosidad.

Un saludo,
LoPiTaL

LoPiTaL
24-05-2010, 21:39:07
Bueno, como te he dicho sentía curiosidad. escafandra tenía razón, sólo que no basta con darle el foco (Windows.SetFocus no me funcionaba :( ). He tenido que hacer BringWindowToTop. Además no me funciona ni en el evento OnCreate ni en el OnShow del form, sino que he tenido que hacerlo en un timer (de 1 ms claro).

El código:


procedure TForm1.Timer1Timer(Sender: TObject);
var
wnd: HWND;
begin
Timer1.Enabled:=False;
wnd := FindWindow (nil,'Sin título - Bloc de notas'); //encuentra la nueva ventana

BringWindowToTop(wnd);
keybd_event(VK_CONTROL, 0, 0, 0);
keybd_event($41, 0, 0, 0); //En castellano es Ctrl+'A'
keybd_event($41, 0, KEYEVENTF_KEYUP, 0);
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
end;


Pruébalo a ver qué tal y nos dices.

PD: Si alguien puede explicar por qué el postmessage y sendmessage no funcionan se agradecería.

Un saludo,
LoPiTaL

LoPiTaL
25-05-2010, 08:54:44
Para terminar mi monólogo sólo una pregunta más: ¿la aplicación que pretendes controlar la has desarrollado tú? ¿O es de terceros? Si la desarrollas tú (y te apetece marearte mucho) podrías echarle un vistazo a la automatización mediante OLE / COM. Con esto se pueden hacer verdaderas virguerías.
Si no la has hecho tú, tal vez hayan implementado en esta aplicación algo de automatización...
Te indico unos ejemplos: el Office lleva automatización, por eso se puede usar el corrector ortográfico en un montón de aplicaciones fuera de Office, o abrir documentos en otro sitio que no sea el Word (como lo hace el explorer cuando abres un .doc).

Un saludo, y espero haber ayudado (la intención era buena :D )
LoPiTaL

oabel5
25-05-2010, 10:22:32
Hola LoPiTal,
SUPEEER!!!!!!!
por eso sabía que no me equivoqué al poner mi pregunta en este foro. Todavía no probé el código que indicas (lo haré mas tarde), pero ya puedo ver que es la solución a mi problema. Ahí te aviso.
El otro programa que quiero manipular no es mio, pero gracias a un programa que en este momento no me acuerdo cual era, pude indagar todos los Handles que este poseía, por esa razón creo que a partir de tu código lograré realizar lo que quiero.
Saludos.
Abel.

oabel5
25-05-2010, 13:34:57
Hola,
tenían razón, la idea de Escafandra mas la implementación de LoPiTal era la solución a mi problema. Logré abrir la ventana de esa otra aplicación con esto:
wnd = FindWindow (NULL,"ECU Flash Tool");
BringWindowToTop(wnd);
keybd_event(VK_CONTROL, 0, 0, 0);
keybd_event(0x4F, 0, 0, 0); // Ctrl+'O'
keybd_event(0x4F, 0, KEYEVENTF_KEYUP, 0);
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);

el siguiente paso es, cómo introduzco una ruta en el espacio donde se indica cual archivo se abrirá. Haré un par de experimentos, talvez lo logre hoy mismo.
Preparé un documento en PDF, ahí indico exáctamente de lo que trato de hacer con mi programa. Hay alguna forma de pegar ese PDF en este foro?
Espero que este hilo no acabe tan pronto, porque estuve investigando todo el fin de semana sobre este tema y me dí cuenta que hay mucha gente que está interesada sobre el caso pero que no encontraron una solución.
Saludos y nuevamente gracias.
Abel.

LoPiTaL
25-05-2010, 14:55:15
No puedes subir ningún archivo hasta que no llegues a 10 mensajes :( (ya llevas 6, queda poco queda poco....) La verdad es que sería interesante que subieses tanto el pdf ese como indicases qué programa usaste para detectar los handles de las aplicaciones.

Ya nos vas contando tus progresos.

Un saludo,
LoPiTaL

oabel5
25-05-2010, 15:18:55
enviaré unos mensajes fantasma, para llegar a los diez mensajes.

oabel5
25-05-2010, 15:21:19
lo del programa que detecta los Handles de otros programas, como mencioné no me acuerdo cómo se llama. En este momento me encuentro en el trabajo, mañana recien podré indicarles cual es ese programa, porque lo tengo en el Portatil en casa.

oabel5
25-05-2010, 15:21:53
Bueno, ya llevo ocho mensajes; con este nueve.

oabel5
25-05-2010, 15:23:05
Este sería mi mensaje número diez. Veamos si ahora puedo subir ese archivo.

oabel5
25-05-2010, 15:26:16
Ahí está; me acabo de dar cuenta que tiene que estar comprimido en .zip y no en .rar.
Desearía que lo vieras y me hagas algún comentario al respecto.
Saludos.
Abel

LoPiTaL
25-05-2010, 16:02:03
No me parece mucho más complicado de lo que acabamos de hacer, si eres capaz de hacerlo todo sólo mediante teclado.

Lo más inmediato que se me ocurre es contar el nº de veces que pulsas "tab" para llegar a los edits que quieres completar y "escribir" lo que quieras. Lo mismo para llegar a los botones y "escribir" un "enter".
Lo difícil será presionar la imagen esa de "Communication Settings" si no puedes llegar a ella con acceso rápido o con tabulaciones.

Tal vez una solución más "elegante" (no la he probado,sólo teórica) sería usar la función GetWindow con parámetros GW_CHILD y GW_HWNDNEXT e ir probando hasta que dieses con el Edit en cuestión (NOTA: los edit se tratan como ventanas hijas de la ventana principal). He llegado a esta conclusión haciendo pruebas con ele Notepad y viendo que la ventana padre (FindWindow (NULL,"Unbenannt - Editor");) tiene dos hijos (doy por sentado, sin probarlo, que serían el menú y el edit) y que por eso esta función te permitía escribir en la "ventana Edit" FindWindowEx(wnd,0,"Edit",NULL); , que realmente es un Edit y no un Window. NO ESTOY SEGURO DE ESTO ÚLTIMO.

La solución de las tabulaciones seguro que es infinitamente más sencilla que la otra....

Un saludo,
LoPiTaL

oabel5
25-05-2010, 16:13:08
Ya me acordé que ese programa que leía los Handles de otros programas lo tenía grabado en mi Flash. Aqui les adjunto.
Saludos.
Abel

oabel5
25-05-2010, 16:24:01
La solución de las tabulaciones seguro que es infinitamente más sencilla que la otra....

Un saludo,
LoPiTaL
tambien había pensado en lo mismo, lo probaré mas tarde.
Me olvidaba, si haces correr el WinCtrl, en la parte de abajo al medio, hay un cuadrito que tienes que marcarlo, sinó no puedes hacer nada. Eso solo te indica que lo que vayas a hacer es tu responsabilidad (está todo en alemán).
Tambien tengo el código de este programa, pero muchas cosas no lo entendí. Como te darás cuenta, con este puedes manipular otras aplicaciones.
Saludos.
Abel.

LoPiTaL
26-05-2010, 08:47:02
Es interesante el programa este, no soy capaz de hacer gran cosa con él, pero demuestra que se puede acceder a todas las "ventanas" de una aplicación, como ya te había comentado, tanto a los edits como a los forms, etc... y de hecho si utilizas el botón ese de "Send Command" a cualquiera de ellos lo que hace es cambiarle el texto, ya sea el Caption en los labels, forms, etc... o el Text en los Edits... Lo malo es que no todas las "ventanas" tienen nombre (o al menos no aparece), entonces no sabes realmente a cuál de ellas le estás mandando cosas si no vas probando... y claro, tal y como te avisa la aplicación, "es tu responsabilidad" :D

Un saludo,
LoPiTaL

oabel5
26-05-2010, 09:58:34
estuve haciendo experimentos y no logro meter la ruta en la ventana "Abrir". Esto es lo que hice:
char s[200]="O:\\NU\\Projects\\FuA\\CC_EL\\Centerdaten\\ECU_Test\\Projects\\DQ200_G2\\Tools\\EcuFlashTool\\FlashM onitorEOL\\DQ200G2_Flash_Monitor_EOL.ini";

wnd = FindWindow (NULL,"ECU Flash Tool");
BringWindowToTop(wnd);
keybd_event(VK_CONTROL, 0, 0, 0);
keybd_event(0x4F, 0, 0, 0);
keybd_event(0x4F, 0, KEYEVENTF_KEYUP, 0);
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);

wnd = FindWindow (NULL,"Open File");
BringWindowToTop(wnd);

for( i= 0;i<= strlen(s);i++)
{
keybd_event((int)s[i], 0, 0, 0);
keybd_event((int)s[i], 0, KEYEVENTF_KEYUP, 0);
}

el problema es que los signos ":" y "\" no los quiere escribir. Tienes alguna idea de cómo añado estos signos?
Saludos.
Abel.

oabel5
26-05-2010, 13:09:20
Hola a todos,podría por favor alguien traducirme esto a C, yo me hice un rollo y no me resulta.
Gracias de antemano.
Abel.
procedure Keyb_Event(C: CHAR);
var S: WORD;
begin S:= VkKeyScan(C);
if(S and $0100) <> 0 then keybd_event(VK_SHIFT,0,0,0);
if(S and $0200) <> 0 then keybd_event(VK_LCONTROL,0,0,0);
if(S and $0400) <> 0 then keybd_event(VK_LMENU,0,0,0);
keybd_event(S,0,0,0);
keybd_event(S,0,KEYEVENTF_KEYUP,0);
if(S and $0100) <> 0 then keybd_event(VK_SHIFT,0,KEYEVENTF_KEYUP,0); i
f(S and $0200) <> 0 then keybd_event(VK_LCONTROL,0,KEYEVENTF_KEYUP,0);
if(S and $0200) <> 0 then keybd_event(VK_LMENU,0,KEYEVENTF_KEYUP,0);
end;

LoPiTaL
26-05-2010, 14:38:22
estuve haciendo experimentos y no logro meter la ruta en la ventana "Abrir". Esto es lo que hice:
char s[200]="O:\\NU\\Projects\\FuA\\CC_EL\\Centerdaten\\ECU_Test\\Projects\\DQ200_G2\\Tools\\EcuFlashTool\\FlashM onitorEOL\\DQ200G2_Flash_Monitor_EOL.ini";

wnd = FindWindow (NULL,"ECU Flash Tool");
BringWindowToTop(wnd);
keybd_event(VK_CONTROL, 0, 0, 0);
keybd_event(0x4F, 0, 0, 0);
keybd_event(0x4F, 0, KEYEVENTF_KEYUP, 0);
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);

wnd = FindWindow (NULL,"Open File");
BringWindowToTop(wnd);

for( i= 0;i<= strlen(s);i++)
{
keybd_event((int)s[i], 0, 0, 0);
keybd_event((int)s[i], 0, KEYEVENTF_KEYUP, 0);
}

el problema es que los signos ":" y "\" no los quiere escribir. Tienes alguna idea de cómo añado estos signos?
Saludos.
Abel.

Es bastante sencillo si utilizas la función VkKeyScan: esta devuelve qué valor tienes que pasarle al keybd_event para escribir el caracter que quieras, así como el estado del shift, ctrl, alt, etc... Te pongo un ejemplo:


var
auxWord: Word;
auxChar: byte;
begin
laStr:='C:\HOLA\HOLA2';

//Para todos los chars
for I := 1 to length(laStr) do begin
auxWord:=VkKeyScan(laStr[I]); //Escaneamos el char en concreto

//Según la ayuda de la función, en el byte menos significativo tenemos
//el valor del char a pasarle a keybd_event, y en el byte más significativo
//tenemos el estado del shift, ctrl y alt. NO distingue entre alt, ctrl, shift
//izdos y drchos, pero dado que no puede ser el alt izdo (si no, no escribiría
//nada, pongo el derecho (de ahí que sea VK_RMENU y no VK_MENU)).

auxChar:=(auxWord and $FF);

if (auxWord and $100)<>0 then
keybd_event(VK_SHIFT, 0, 0, 0)
else if (auxWord and $400)<>0 then
keybd_event(VK_RMENU, 0, 0, 0);

keybd_event(auxChar, 0, 0, 0);
keybd_event(auxChar, 0, KEYEVENTF_KEYUP, 0);

if (auxWord and $100)<>0 then
keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0)
else if (auxWord and $400)<>0 then
keybd_event(VK_RMENU, 0, KEYEVENTF_KEYUP, 0);
end;

//Finalmente pulsamos enter:
keybd_event(VK_RETURN, 0, 0, 0);
keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);



A mí me ha funcionado a la perfección.

Un saludo,
LoPiTaL

escafandra
26-05-2010, 15:32:51
Hola a todos,podría por favor alguien traducirme esto a C...
Esa función la escribí yo para resolver la duda que ahora presentas y ya la traduje aquí (http://clubdelphi.com/foros/showpost.php?p=365093&postcount=5). El problema es que con keybd_event no se pueden simular caracteres conseguidos con teclas modificadoras como AltGr (Ctl+Alt). Por ese motivo escribí una nueva versión que ahora te vuelvo a presentar:

// El parámetro C es el carácter que queremos escribir.
Keyb_Event(char C)
{
WORD S = VkKeyScan(C);
if(S & 0x0100) keybd_event(VK_SHIFT,0,0,0);
if(S & 0x0200) keybd_event(VK_LCONTROL,0,0,0);
if(S & 0x0400) keybd_event(VK_LMENU,0,0,0);

keybd_event(S,0,0,0);
keybd_event(S,0,KEYEVENTF_KEYUP,0);

if(S & 0x0100) keybd_event(VK_SHIFT,0,KEYEVENTF_KEYUP,0);
if(S & 0x0200) keybd_event(VK_LCONTROL,0,KEYEVENTF_KEYUP,0);
if(S & 0x0400) keybd_event(VK_LMENU,0,KEYEVENTF_KEYUP,0);

}

Saludos.

oabel5
26-05-2010, 15:55:57
Esa función la escribí yo para resolver la duda que ahora presentas y ya la traduje aquí (http://clubdelphi.com/foros/showpost.php?p=365093&postcount=5). El problema es que con keybd_event no se pueden simular caracteres conseguidos con teclas modificadoras como AltGr (Ctl+Alt). Por ese motivo escribí una nueva versión que ahora te vuelvo
Saludos.

Si, justamente de casualidad lo encontré en otro hilo donde habías colocado ese código hace nueve días creo.
Justamente a mi no me resultaban esos Caracteres: ":", especialmente el "\", pero ahora implementé tu código a mi programa y .... por fin.
Muchas gracias por vuestro tiempo y las respuestas.
Esta tarde seguiré implementando mi programa, mi siguiente desafío es hacer que de alguna forma tengo que simular que presiono con el ratón en el "Communication Settings" (pueden ver el PDF que adjunté antes). La idea que me dió LoPiTal sobre usar el TAB varias veces hasta encontrar este ícono, en este caso no resulta :(; solo se puede acceder a esa ventana usando el ratón. Talvez ustedes tienen otra idea, les agradecería.
Saludos
Abel.

escafandra
26-05-2010, 20:37:36
Revisa esto (http://www.clubdelphi.com/foros/showthread.php?t=65039&highlight=MouseClick).

Saludos.

oabel5
27-05-2010, 07:04:41
Hola Escafandra,
lo acabo de probar y funciona, gracias por ese aporte.
Ahora realizaré lo demas que ya no es problema.
Saludos desde Berlin.
Abel