PDA

Ver la Versión Completa : ¿Puntero a objeto asignando su handle?


aguml
25-12-2014, 17:38:48
imaginen que tengo un tedit llamado ed1 y hago TEdit ed2 = new *TEdit; y luego ed2->Handle = ed1->Handle; si hago ed->Text = "hola"; ¿Que padaria? ¿Apareceria eñ texto en ambos? Es que necesito acceder a los metodos de un objeto del cual solo tengo su hwnd y es lo unico que se me ocurre.

escafandra
25-12-2014, 20:49:47
No puedes asignar un TEdit::Handle a otro TEdit pues es de solo lectura. Yo haría algo como esto:

TEdit* E = (TEdit*)FindControl(Edit1->Handle);
E->Text = "Hola";



Saludos.

aguml
26-12-2014, 01:58:26
interesante. Tengo que probarlo y ya os cuento.

aguml
26-12-2014, 10:40:27
tengo una duda al respecto. El componente funciona desde un ocx que vale para varios programas (entre ellos delphi, c++builder, o Visual basic). El componente se usa en una aplicacion en VB donde yo injertaria codigo para que cargue mi dll y para que ejecute mi funcion de la dll. Si hago en la funcion de mi dll uso de FindWindow, y FindWindowEx obtendria un hwnd del componente y, si pongo lo que dices para asignar el objeto a mi puntero ¿Crees que funcionaria o al ser plataformas diferentes podria tener problemas? Uso el mismo ocx tanto para la aplicacion como para la dll.

Ñuño Martínez
26-12-2014, 11:20:33
¿Te refieres a qué pasará si usas el código sugerido por Escafandra para obtener un control creado por VB? Pues creo que la única forma de saberlo es intentándolo. Aun así, es posible que falle ya que la descripción de la clase contenedora en VB diferirá del de la clase contenedora en Builder. Claro que quizá la función FindControl sea capaz de lidiar con ello, ya que el Handle es suficiente para controlar cualquier control.

escafandra
26-12-2014, 13:19:40
Como dice Ñuño Martínez lo esperable es que falle. Mejor intenta informarte del componente de VB, para manejarlo desde la API de Windows en la medida que sea posible.

Saludos.

aguml
26-12-2014, 14:42:13
Lo he probado en un ejemplo creado por mi y no me funciona. Tengo esto:

App:
void __fastcall TForm1::AddDll()
{
//cargamos la Dll
Dll=LoadLibrary("DllSaveImageEdited.dll");
if(!Dll){
ShowMessage("No se encontró la Dll: DllSaveImageEdited.dll");
}else{
//buscamos la funcion en la dll
Funcion = (LPFuncion)GetProcAddress(Dll, "SaveImageEdited");
if(!Funcion){
ShowMessage("ERROR, no se encontró la función: SaveImageEdited");
}else{
Funcion();//Ejecutamos la funcion de la dll

ButtonDesinstalarDll->Enabled = true;
ButtonInyectarDll->Enabled = false;
}
}
}

Dll:
#include <windows.h>
#include "C:\\Archivos de programa\\Borland\\CBuilder6\\Imports\\AddFlow5Lib_OCX.h"
//---------------------------------------------------------------------------

#pragma argsused

/*******************************************************/
/*FUNCIÓN PARA INSTALAR/DESINSTALAR EL HOOK DEL TECLADO*/
/*******************************************************/
extern "C" __declspec(dllexport) __stdcall int SaveImageEdited(void)
{
int retval;

try
{
//Para la prueba
HWND hwnd = FindWindow("TForm1", "Form1");
hwnd = FindWindowEx(hwnd, NULL, "AfxOleControl42", NULL);

//Obtengo un puntero a dicho componente con su handle
TAddFlow* paf = (TAddFlow*)FindControl(hwnd);

if(paf!=NULL) {
paf->SaveImage(afTypeMediumFile, afWMF, WideString("\\DiagramaEditado.wmf"));
retval = 0;
}else{
MessageBoxA(NULL,"El puntero no es válido.", "Error", MB_OK | MB_ICONERROR);
retval = -2;
}
}
catch(...)
{
retval = -1;
}
return retval;
}
//---------------------------------------------------------------------------

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
return 1;
}
//---------------------------------------------------------------------------

El control es de clase "AfxOleControl42" y consigo su hwnd sin problemas pero FindControl retorna 0, o sea que no me devuelve la direccion y por tanto se muestra el mensaje de que el puntero no es valido.
¿que puede estar fallando? ya digo que es una prueba que hice en C++builder tanto la app como la dll.

En la aplicacion el componente se declara:
TAddFlow *AddFlow1;

escafandra
26-12-2014, 14:50:43
Quizás con FindComponent...

Saludos.

aguml
26-12-2014, 16:00:13
¿Como seria con FindComponent? He mirado la ayuda y veo que recibe como parametro un AnsiString pero no se que poner ahi y ademas doy al ejemplo y no aparece ni la funcion en el ejemplo.
Si es el Name no lo tendria en el de VB.

mamcx
26-12-2014, 17:54:43
Y para que quieres hacer esto?

Es mala idea tratar de romper el "contrato" de lo que cualquier API te suministre, EN ESPECIAL si intentas hacer una mutacion/cambio de estado o romper con el proposito de lo que hace esa API.

aguml
26-12-2014, 19:21:05
no no, es para implementar mas cosas que la app no hace y que podria hacerlo sin problemas ya que usa un objeto el cual trae consigo esos metodos. No hay que romper apis ni nada, solo llamar a metodos que ya existen y el fabricante no los usa. Imagina una clase con los metodos Draw, SaveImage, SaveFile, Clear y Refresh, imagina que alguien usa esa clase en una aplicacion y solo usa Draw y Refresh y ¿Por que no usa el resto? El sabrá pero en mi debugger me gustaria implementar la opcion de que pueda usar cualquier metodo de esa clase y para ello necesito el puntero de la clase para poder trabajar con sus metodos, propiedades o lo que sea.

mamcx
26-12-2014, 20:56:57
Pues eso que dices es romper el API. Si esta escondiendo el metodo (que es una de las razones de la OO: encapsulamiento ) es porque llamarlos puede causar problemas, o no tiene implementacion o carece de sentido.

aguml
26-12-2014, 21:14:43
en este caso tiene sentido, es util y estáimplementado en la ocx. La ocx es de pago pero se puede usar gratis para uso no comercial y la unica limitacion es una nag que te dice que fue creada con la version sin licencia pero funciona perfectamente. Que la app no use sus metodos no significa nada, trae metodos para exportar, guardar, y muchisimos mas, ya hice una prueba y va perfecto en mi aplicacion pero claro, yo le paso el puntero a la funcion de mi dll y mi dll hace TAddFlow *af=(TAddFlow*)puntero; y luego hago af->SaveImage("imagen.wmf");. El problema está en obtener el puntero cuando se hace con otra app que solo tengo el binario.

aguml
27-12-2014, 10:38:26
despues de mucho tracear mi aplicacion de ejemplo veo que usa AddRef y que al entrar en ella, en ESP+0xC tengo lo que busco. El caso es que ahi para continuamente y no es un lugar apropiado para obtener lo que quiero aunque alguien me dijo que podria ir asignando dicho valor a mi puntero y dentro de un manejador probar a ejecutar un metodo o propiedad y si funciona bien es el valor correcto y si no pues no lo es. El caso es que he leido que AddRef es un metodo de los objetos COM y que lo que hace es aumentar el contador de referencias a la interface. Segui buscando y lei que QueryInterface necesita dos parametros, el primero un identificador que no se que tipo será y el segundo es donde recupera el puntero a la interface. El caso es que no he podido probar si llama a QueryInterface para ver si por ahi puedo obtener lo que busco por falta de tiempo (a ver si puedo el lunes) pero me surge una duda, el control es ActiveX, AddRef y QueryInstance son metodos de objetos COM, y AddRef pude ver que es llamada desde algo como COleImport o algo asi ¿ActiveX, COM, y OLE son lo mismo? Es que lo que he podido leer no me deja nada claro.

Ñuño Martínez
29-12-2014, 12:26:32
¿ActiveX, COM, y OLE son lo mismo? Es que lo que he podido leer no me deja nada claro. Sí y no. Si no recuerdo mal, ActiveX y COM son versiones más avanzadas de OLE, o sea, que están basados o inspirados en OLE. Por otro lado, los tres protocolos te permiten usar componentes de otras aplicaciones o controlar otras aplicaciones.

aguml
29-12-2014, 17:27:54
entonces doy por hecho que FindControl no funciona con objetos OLE y supongo que FindComponent tampoco servirá. ¿Que se usa entonces para los ActiveX? He estado leyendo que CoCreateInstance crea una instancia y nos da el puntero a la instancia pero la aplicacion no la usa y supongo que es porque se crea en tiempo de diseño ya que es un componente visual. El nombre del componente en la otra aplicacion no lo tengo pero si en mi aplicacion de prueba asi que podria probarlo en la mia solo. Ni spy++, ni Resource tuner ni nada me dan el nombre del componente asi que no puedo ni intentarlo. Sabeis alguna manera de conseguir el puntero pero para un ActiveX?
Encontre esto: http://msdn.microsoft.com/en-us/library/windows/desktop/ms684007(v=vs.85).aspx
¿Es lo que necesito? Y si es asi ¿Podeis ayudarme a entender como usarla? Es que mi ingles es malisimo y ademas hay cosas que no se ni a que se refieren.

aguml
02-01-2015, 17:49:14
problema solucionado amigos. Explico la solucion. Me cree una dll en c++builder con las funciones necesarias y luego la cargué en el proceso. La aplicacion usa QueryInterface asi que con poner un bp ahi obtengo el puntero al objeto el cual almaceno. Luego llamo a las funciones de la dll y funciona asi que pruebo con la aplicacion echa en vb y veo que da errores y no sirve por lo que empiezo apensar que no se puede usar esta dll en vb y pido a un amigo que me cree una dll en vb con las mismas funciones y la pruebo y funciona sin problemas. Ahora me encontraba con otro problema, la imposibilidad de usar LoadLibrary, GetModuleHandle, y GetProcAddress para cargar mi dll dinamicamente. Entonces miré las funciones de la dll en un depurador y veo que las unicas constantes que habria que modificar serian la llamada a una funcion de vb que viene en la iat y el puntero a ruta del proceso. Entonces pensé ¿Que pasaria si usase VirtualAllocEx para solicitar la memoria necesaria y luego copio las funciones a esa zona, redirijo el puntero de la ruta del archivo y inyecto codigo para ejecutar cada funcion.