Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   C++ Builder (https://www.clubdelphi.com/foros/forumdisplay.php?f=13)
-   -   Enviar texto a Edit de ventana ajena (https://www.clubdelphi.com/foros/showthread.php?t=94620)

aguml 29-04-2020 23:29:49

Enviar texto a Edit de ventana ajena
 
Buenas me gustaría poder buscar una ventana y si la encuentra mandar texto a un Edit de esa ventana. ¿Podrían indicarme qué funciones del API usar? Para buscar la ventana supongo que con FindWindow o FindWindowEx pero para recorrer todos los componentes de la ventana y leer y escribir en el Edit no sé cómo sería.

ecfisa 30-04-2020 06:26:03

Hola.

No sé si es lo que andas buscando, pero te pongo un ejemplo que cambia el contenido del TEdit indicado en la ventana especificada.
Código PHP:

#include<iostream>
#include<string>
#include<windows.h>

void sendTextToEdit(const charappTitle, const charclassName,
  const 
charctrlName, const chartext)
{
 
HWND hParenthChild;

  
hParent FindWindow(NULLappTitle);
  if (
hParent) {
    
hChild FindWindowEx(hParent0classNamectrlName);
    if (
hChild)
      
SendMessage(hChildWM_SETTEXT0, (LPARAM)text);
    else
      
MessageBox(0"Ventana hija no encontrada."""MB_ICONERROR);
  }
  else
    
MessageBox(0"Ventana padre no encontrada."""MB_ICONERROR);
}


int main()
{
  
std::string wndName "Form1";
  
std::string editName "Edit1";  

  
sendTextToEdit(wndName.c_str(), "TEdit"editName.c_str(),
    (
"NUEVO TEXTO EN "+editName).c_str());


Saludos :)

aguml 30-04-2020 12:28:30

Creo que es justo lo que busco aunque creo que otra vez lo hice y enumeraba todos los componentes y si era el tipo de componente que yo buscaba comparaba el nombre con el que buscaba jejeje. Si me funciona esto es mucho más sencillo que usar un callback.

aguml 01-05-2020 14:31:57

amigo tengo un problema con tu codigo, mas bien es lo que pedia pero no lo que realmente necesito ya que no tengo el nombre del componente pero si tengo su clase y su ItemID. Adjunto imagen de la info que obtengo que creo que es la que mas interesa:

¿Como puedo hacer eso mismo pero por su ItemID en vez de por su nombre?
Gracias por adelantado.

aguml 01-05-2020 19:53:47

Ya lo conseguí.

ecfisa 01-05-2020 20:09:19

Hola.

Te estaríamos muy agradecidos si nos compartieras como.

Saludos :)

Casimiro Notevi 01-05-2020 20:11:36

La otra guía de estilo:
Si encuentras la solución tú mismo, no te molestes en explicarla. Bastará con un "Ya lo resolví". Nos emociona ver gente autosuficiente.

aguml 01-05-2020 21:50:36

Lo siento, ya lo pongo:
Código PHP:

//Funcion para enviar texto a un TEdit
void sendTextToEdit(const charappTitle,
  
int ResId, const chartext)
{
    
HWND hParenthChild;

    
hParent FindWindow(NULLappTitle);
    if (
hParent) {
        
hChild GetDlgItem(hParent,ResId);
        if (
hChild)
            
SendMessage(hChildWM_SETTEXT0, (LPARAM)text);
        else
            
MessageBox(0"No se pudo enviar el serial a la ventana.\n¿Tienes abierta la ventana?""Error"MB_ICONERROR);
    }
    else
        
MessageBox(0"No se encontró la ventana.\n¿Tienes abierta la ventana?""Error"MB_ICONERROR);
}
//---------------------------------------------------------------------------

//Funcion para obtener el texto de un TEdit
AnsiString getTextFromEdit(const charappTitleint ResId)
{
    
HWND hParenthChild;
    
int TxtLen;
    
char txtFinal[50];

    
hParent FindWindow(NULLappTitle);
    if (
hParent) {
        
hChild GetDlgItem(hParent,ResId);
        if (
hChild){
            
//Leo lo que hay en el Edit
            
TxtLen SendMessage(hChildWM_GETTEXTLENGTH00);
            
SendMessage(hChildWM_GETTEXTTxtLen 1, (LPARAM)txtFinal);
        }else{
            
MessageBox(0"No se pudo leer el Edit de la ventana.\n¿Tienes abierta la ventana?""Error"MB_ICONERROR);
        }
    }
    else{
        
MessageBox(0"No se encontró la ventana.\n¿Tienes abierta la ventana?""Error"MB_ICONERROR);
    }

    return 
txtFinal;



Casimiro Notevi 01-05-2020 22:19:46

^\||/^\||/^\||/

aguml 04-05-2020 13:01:57

Tengo una duda, he probado a sustituir SendMessage por SetWindowText y GetWindowText y no me funciona. Según he leído en la msdn se usan para enviar y leer texto de controles de otras aplicaciones. ¿Habría que hacer algo más a parte de sustituir una por otra?

escafandra 04-05-2020 13:48:41

Cita:

Empezado por aguml (Mensaje 537040)
Tengo una duda, he probado a sustituir SendMessage por SetWindowText y GetWindowText y no me funciona. Según he leído en la msdn se usan para enviar y leer texto de controles de otras aplicaciones. ¿Habría que hacer algo más a parte de sustituir una por otra?

Para leer el texto de un Edit de una aplicacion ajena a la tuya, no funciona SetWindowText y GetWindowText, sólo se puede hacer a través de
Código PHP:

SendMessage(hWndWM_GETTEXT,  BuffSize, (LPARAM)Buffer); 

Saludos.

aguml 04-05-2020 14:44:31

"Changes the text of the specified window's title bar (if it has one). If the specified window is a control, the text of the control is changed. However, SetWindowText cannot change the text of a control in another application."
Lo leí mal, tienes razón, no sirve para cambiar texto en otras aplicaciones.
Tengo otra duda, el código funciona genial pero me gustaría automatizarlo, me explico:
La aplicación tiene un cuadro de diálogo el cual crea con DialogBoxParamA y se en que parte de la aplicación hace la llamada a ese cuadro de diálogo y la idea es crearme un pequeño debuger que lo ejecute y que cuando salga ese cuadro de diálogo ya aparezca con el texto que quiero enviar pero no sé si es posible hacer algo así porque depurando la aplicación veo que al ejecutar la línea que muestra el cuadro de diálogo ya no vuelve al código hasta que obtenga una respuesta al igual que pasa con los MessageBox.

escafandra 04-05-2020 19:59:55

Si tienes el código, modifícalo.
Si quieres cambiar texto desde una app externa con WM_SETTEXT, piensa que hasta que no se cree el diálogo no podrás enviar mensajes y que el dialogo puede resistirse al cambio porque tiene su propia función de tratamiento de mensajes.
Otra opción es hacer un subclassing cambiando lpDialogFunc, eso lo puedes hacer con un hook a la API DialogBoxParamA con código inyectado.

Una Ultima Opción es hacer un escaner de la memoria del proceso para detectar la cadena que pretendes cambiar. El cambio tiene que ser en idéntica longitud de caracteres o menor, terminada en cero. Nunca mayor.


Si lo que pretendes es cambiar varios comportamientos del cuadro de dialogo, la mejor opción es el subclassing.


Saludos.

aguml 04-05-2020 20:16:56

Me han comentado que una opción es liberar a la aplicación de mi depurador y luego enviarle el texto, cosa que me valdría porque es lo único que tiene que hacer, pero eso tiene un pero ¿Como hago para saber cuándo enviar el texto? ¿Un timer? No se me ocurre como. Cuando desatacheo un depurador ¿Iría al mismo evento que cuando terminó el proceso o son eventos diferentes?
Las opciones que me indicas me sobrepasan de largo ��.

escafandra 04-05-2020 22:45:11

Cita:

Empezado por aguml (Mensaje 537055)
Me han comentado que una opción es liberar a la aplicación de mi depurador y luego enviarle el texto, cosa que me valdría porque es lo único que tiene que hacer, pero eso tiene un pero ¿Como hago para saber cuándo enviar el texto? ¿Un timer? No se me ocurre como. Cuando desatacheo un depurador ¿Iría al mismo evento que cuando terminó el proceso o son eventos diferentes?
Las opciones que me indicas me sobrepasan de largo ��.

Con un Timer puedes ver si la ventana se está ejecutando, pero tienes un problema de eficiencia. Si el periodo es muy largo te pierdes momentos y si es muy corto, estás ejecutando la búsqueda siempre. El Hook solo se ejecuta cuando se ejecuta la API DialogBoxParamA pero en mas laborioso.

Saludos.

aguml 06-05-2020 00:01:06

Pero no entiendo algo. Supongamos que creo un Hook a esa función ¿Como sabría cuando terminó de mostrar la ventana para enviar el texto?

aguml 06-05-2020 00:47:15

Un ejemplo de Hook que vi fue esto:
Código PHP:

LRESULT CALLBACK MyCbtHook(int nCode,  WPARAM wParam,  LPARAM lParam)
{
    switch(
nCode)
    {
    case 
HCBT_CREATEWND:
        {
            
HWND hWnd = (HWND)wParam;
            
TRACE("A window is being created, HWND = %p\n"hWnd);
            break;
        }
    }

    return 
CallNextHookEx0nCodewParamlParam );
}

void InstallHook()
{
    
SetWindowsHookEx(WH_CBTMyCbtHook0GetCurrentThreadId());


¿Sería algo así? O tendría que crear una dll e inyectarla para hacer eso que dices?

escafandra 06-05-2020 01:35:54

Dado que se trata de una aplicación externa, la técnica es un hook a la API mediante inyección de código en una dll (puede ser inyección directa pero es más complejo). Este tipo de hook intercepta la API, es decir, tu código es la misma API con lo que lo sabes todo. Tienes un tutorial aquí.

Saludos.

escafandra 06-05-2020 01:42:14

Dado que se trata de una aplicación externa, la técnica es un hook a la API mediante inyección de código en una dll (puede ser inyección directa pero es más complejo). Este tipo de hook intercepta la API, es decir, tu código es la misma API con lo que lo sabes todo. Tienes un tutorial aquí. Ahora me doy cuenta de que ese enlace ya lo conocías desde junio de 2014

Saludos.

aguml 06-05-2020 14:36:26

Vale gracias, de momento estoy intentando desatachearme del proceso y tengo un problema, cuando lo hago me da Error 5 que es "Acceso denegado". El inicio de la funcion donde creo el proceso que voy a depurar es así:
Código PHP:

        DEBUG_EVENT DebugEv;
        
HANDLE CurrentExceptionThread;
        
DWORD dwContinueStatus;

        
TDll *ItemDLL;

        
bool salir=false;

        
ListaBPs = new TList;
        
ListaDlls = new TList;
        
ListaThreads = new TList;

        
Synchronize(OnInitLoopDebugThread); //Usaremos este evento para inizialización de variables en la clase usuario si se requiere.

        
si.cb sizeof(STARTUPINFO);
        
GetStartupInfo(&si);
        
// El proceso se tiene que crear en la misma función donde está el hilo del depurador sino no vale
        
CreateProcess(PathFile.c_str(),NULLNULLNULLFALSEDEBUG_PROCESS DEBUG_ONLY_THIS_PROCESSNULLNULL, &si, &pi); 

Y en otra funcion hago esto:
Código PHP:

if(DebugActiveProcessStop(pi.dwProcessId) == 0){
        
ShowMessage(GetLastError());
    } 

El mensaje es para ver que error me estaba dando y me muestra que es el 5 y segun la lista de errores es que me está denegando el acceso. ¿que hago mal para que no me deje desatachearme? :confused:


La franja horaria es GMT +2. Ahora son las 04:01:56.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi