Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 17-07-2006
Avatar de ixMike
ixMike ixMike is offline
Miembro
 
Registrado: feb 2004
Posts: 1.151
Poder: 22
ixMike Va por buen camino
DLLs con nombre desconocido

Hace cosa de una semana (o un poco más) pregunté cómo llamar a funciones de DLLs cuyo nombre desconozco. La respuesta de seoane me sirvió mucho, pero no me lo solucionó del todo, ya que una de las funciones a las que llamo mantiene una ventana abierta, por lo que no puedo llamar a FreeLibrary en la misma función, sino de otra forma.
Tras hacer varias pruebas y ojear el archivo MAPI.PAS que se encuentra en DELPHI\Source\RTL\WIN\ (al menos en la versión que tengo) logré llegar a una solución.
Primero en type declaro los tipos de función que voy a necesitar.
Código Delphi [-]
  {...}
type
  TShowCursorProc = function(bShow: BOOL) : HResult; stdcall;
  TForm1 = class (TForm)
  {...}
Después coloco una variable global para el manejador de la DLL, y todas las variables necesarias para almacenar todas las funciones. Todo tiene que estar inicializado.
Código Delphi [-]
  {...}
var
  Form1: TForm1;
  HandleDLL: THandle = 0;
  FuncionDLL: TShowCursorProc = nil;
  {...}
Creo un procedimiento que inicialice la DLL, a la que puedo llamar por ejemplo cuando cree la ventana, y otra que la libere cuando la cierre.
Código Delphi [-]
{...}
implementation
Procedure InitDLL(dll: string);
begin
If HandleDLL=0 then HandleDLL:=LoadLibrary(PChar(Dll));
end;
Procedure FreeDLL(var Hdll: THandle);
begin
If Hdll<>0 then FreeLibrary(Hdll);
end;
Procedure TForm1.FormCreate(Sender: TObject);
begin
InitDLL('user32.dll');
end;
Procedure TForm1.FormClose(Sender: TObject);
begin
FreeDLL(HandleDLL);
end;
{...}
Ya por último declaro todas las funciones que necesite.
Código Delphi [-]
Procedure MostrarCursor(mostrar: Boolean);
begin
If HandleDLL <> 0 then @FuncionDLL:=GetProcAddress(HandleDll,'ShowCursor');
If @FuncionDLL <> nil then FuncionDLL(mostrar);
end;
También quiero aclarar que en la respuesta de seoane se produce un error de acceso a memoria después de llamar a FreeLibrary. Es una cosa muy rara, porque después puse la línea ShowMessage('Se liberó') y el mensaje se mostraba, y acto seguido salía el error.
Bueno, aunque parezca que lo he solucionado sigo teniendo una gran duda. Y es que HandleDLL almacena el manejador de una libraría, pero yo voy a tener varias librerías, y todas van a tener que estar cargadas a la vez, por lo que no puedo liberar una y cargar otra. Como los nombres de las librerías los almaceno en un TStringList se me ha ocurrido crear un objeto que almacene un array de integers para almacenar en cada uno de ellos el Handle de cada librería.
Si me sale bien lo pondré aquí, pero si alguien me puede ayudar agradeceré muchísimo la respuesta.
Responder Con Cita
  #2  
Antiguo 17-07-2006
Avatar de ixMike
ixMike ixMike is offline
Miembro
 
Registrado: feb 2004
Posts: 1.151
Poder: 22
ixMike Va por buen camino
Lo Tengooooooooooooooooooooooooooo

¡¡¡Lo logré!!!
Primero creé un tipo de objeto parecido al TStrinList, pero que almacena integers en vez de strings. Aquí está el código de la unidad:
Código Delphi [-]
unit Integers;
interface
uses
  Classes;
type
  TIntArray = array [0..0] of Integer;
  PIntArray = ^TIntArray;
  TIntegers = class(TObject)
    protected
    FIntegers: PIntArray;
    FCount: Integer;
    Function GetIntegers(Index: Integer): Integer;
    Procedure SetIntegers(Index: Integer; valor: Integer);
    
    public
    Procedure Add(I: Integer);
    Procedure Clear;
    Procedure Delete(Index: Integer);
    Function IndexOf(I: Integer): Integer;
    Property Count: Integer read FCount;
    Property Values[Index: Integer]: Integer read GetIntegers write SetIntegers;
    Constructor Create;
    Destructor Destroy; override;
    end;
implementation
Constructor TIntegers.Create;
begin
inherited;
GetMem(FIntegers, 0);
FCount:=0;
end;
Destructor TIntegers.Destroy;
begin
FreeMem(FIntegers, FCount * SizeOf(Integer));
inherited;
end;
Procedure TIntegers.Add(I: Integer);
begin
Inc(FCount);
ReallocMem(FIntegers, FCount * SizeOf(Integer));
FIntegers^[FCount-1]:=I;
end;
Procedure TIntegers.Delete(Index: Integer);
var
n: integer;
begin
If FCount=0 then exit;
for n:=Index+1 to FCount-1 do FIntegers^[n-1]:=FIntegers^[n];
Dec(FCount);
ReallocMem(FIntegers, FCount * SizeOf(Integer));
end;
Procedure TIntegers.Clear;
begin
FCount:=0;
ReallocMem(FIntegers, 0);
end;
Function TIntegers.GetIntegers(Index: Integer): Integer;
begin
If Index<=FCount then Result:=FIntegers^[Index];
end;
Function TIntegers.IndexOf(I: Integer): Integer;
var
n: integer;
begin
Result:=-1;
If FCount=0 then exit;
For n:=0 to FCount-1 do If FIntegers^[n]=I then
  begin
  Result:=n;
  exit;
  end;
end;
Procedure TIntegers.SetIntegers(Index: Integer; Valor: Integer);
begin
If index<=FCount then FIntegers^[Index]:=Valor;
end;
end.
Después creé un par de DLLs de ejemplo, con tres funciones que devuelven el nombre de la misma, la versión y el nombre del programador.
Para comprobar que funcionaban, en un nuevo proyecto coloqué un TListView con cuatro columnas (Archivo, nombre, versión, autor). En ella se tendría que listar el nombre de las DLLs encontradas en el directorio de la aplicación y el resultado de las funciones GetName, GetVersion y GetAuthor de las librerías de ejemplo que hice.
Además, las cargo al inicio del programa y las libero al final. Aquí está el códido del programa:
Código Delphi [-]
unit PruebaMain;
interface
uses
  Windows, Forms, ComCtrls, Controls, Classes, SysUtils, Integers;
type
  TGetVersionFunc = function : String; stdcall;
  TGetNameFunc = function : String; stdcall;
  TGetAuthorFunc = function : String; stdcall;
  TForm1 = class(TForm)
    ldlls: TListView;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
  ints: TIntegers;
  vGetName: TGetNameFunc = nil;
  vGetVersion: TGetVersionFunc = nil;
  vGetAuthor: TGetAuthorFunc = nil;
implementation
{$R *.DFM}
Function LiberarLibreria(manejador: Integer): integer;
begin
if manejador<>0 then FreeLibrary(manejador);
Result:=Manejador;
end;
Function CargarLibreria(dll: string): Integer;
begin
Result:=LoadLibrary(PChar(dll));
end;
Function GetName(h: integer): String;
begin
@vGetName:=GetProcAddress(h,'GetName');
if @vGetName <> nil then Result:=vGetName else result:='Error loading library';
end;
Function GetVersion(h: integer): String;
begin
@vGetVersion:=GetProcAddress(h,'GetVersion');
if @vGetVersion <> nil then Result:=vGetVersion else result:='Error loading library';
end;
Function GetAuthor(h: integer): String;
begin
@vGetAuthor:=GetProcAddress(h,'GetAuthor');
if @vGetAuthor <> nil then Result:=vGetAuthor else result:='Error loading library';
end;
procedure TForm1.FormCreate(Sender: TObject);
var
encontrado, n: integer;
archivo: TSearchRec;
nodo: TListItem;
begin
LDLLs.Items.Clear;
// Busca archivos DLL en el mismo directorio
encontrado:=FindFirst(ExtractFilePath(ParamStr(0))+'*.dll',faAnyFile,archivo);
while encontrado=0 do
  begin
  nodo:=ldlls.Items.Add;
  nodo.Caption:=archivo.name;
  encontrado:=FindNext(archivo);
  end;
FindClose(archivo);
////////////
If LDLLs.Items.Count=0 then exit; //Si no ha encontrado DLLs sale
// Asignar handles
ints:=TIntegers.Create;
for n:=0 to LDlls.ITems.Count-1 do
 ints.Add(CargarLibreria(Ldlls.Items[n].caption));
///////////
// Ejecutar funciones
for n:=0 to LDlls.ITems.Count-1 do
  begin
  Ldlls.Items[n].Subitems.Clear;
  Ldlls.Items[n].Subitems.Add(GetName(ints.values[n]));
  Ldlls.Items[n].Subitems.Add(GetVersion(ints.values[n]));
  Ldlls.Items[n].Subitems.Add(GetAuthor(ints.values[n]));
  end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
n: integer;
begin
for n:=0 to ints.Count-1 do ints.values[n]:=LiberarLibreria(ints.values[n]);
ints.Free;
end;
end.
Espero que esto le sirva de ayuda a alguien.
Responder Con Cita
  #3  
Antiguo 17-07-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Je, je, je... bueno. Seguro que lo que dices le sirve de ayuda a más de una persona, estoy seguro. A mí lo que me llamó la atención es que planteases un problema y dieras con la solución (y qué solución) en menos de un minuto.

¡Todo un record de capacidad de respuesta! ¡Cuéntanos cómo lo haces!

Y, en todo caso, gracias por compartir la información con nosotros.

Quiero terminar diciendo que existe un apartado de Trucos en el ClubDelphi en donde tal vez podrías guardar este Hilo, si bien con algunos cambios, para que quedara allí también a disposición de a quien le pudiera hacer menester.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #4  
Antiguo 17-07-2006
Avatar de ixMike
ixMike ixMike is offline
Miembro
 
Registrado: feb 2004
Posts: 1.151
Poder: 22
ixMike Va por buen camino
Thumbs up un poquito de trampa

La verdad es esta:

No tengo Internet en casa . Voy alguna tarde a un ciber .
La pregunta me la planteé en un cierto momento, y estuve como una hora seguida sin parar de teclear, y corregir ...

Ahora he puesto la pregunta y la respuesta por separado para si alguien ve el título, que no lo vea sin respuestas .

Buena observación
Responder Con Cita
  #5  
Antiguo 17-07-2006
[maeyanes] maeyanes is offline
Capo de los Capos
 
Registrado: may 2003
Ubicación: Campeche, México
Posts: 2.732
Poder: 23
maeyanes Va por buen camino
Veo que usas un TListView para obtener la lista de DLL's. Como la clase TListItem tiene una propiedad llamada Data, ahí podrías guardar el Handle de la DLL, así te evitas crear la clase TIntegers.

Aquí te pongo parte de tu código usando la propiedad Data de TListItem:

Código Delphi [-]
procedure TForm1.FormCreate(Sender: TObject);
var
  encontrado, n: integer;
  archivo: TSearchRec;
  nodo: TListItem;

begin
  LDLLs.Items.Clear;
  // Busca archivos DLL en el mismo directorio 
  encontrado:=FindFirst(ExtractFilePath(ParamStr(0))+'*.dll',faAnyFile,archivo);
  while encontrado=0 do
  begin
    nodo := ldlls.Items.Add;
    nodo.Caption := archivo.name;
    nodo.Data := Pointer(CargarLibreria(archivo.Name)); // Guardo el Handle del DLL.
    encontrado:=FindNext(archivo);
  end;
  FindClose(archivo);

  // Ejecutar funciones
  for n:=0 to LDlls.ITems.Count-1 do
  begin
    Ldlls.Items[n].Subitems.Clear;
    Ldlls.Items[n].Subitems.Add(GetName(Integer(LDlls.Items[i].Data)));
    Ldlls.Items[n].Subitems.Add(GetVersion(Integer(LDlls.Items[i].Data)));
    Ldlls.Items[n].Subitems.Add(Integer(LDlls.Items[i].Data)));
  end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
  n: integer;

begin
  for n := 0 to LDlls.Count - 1 do
    LiberarLibreria(Integer(LDlls.Items[i].Data))
end;

Saludos...
Responder Con Cita
  #6  
Antiguo 18-07-2006
Avatar de Neftali [Germán.Estévez]
Neftali [Germán.Estévez] Neftali [Germán.Estévez] is offline
[becario]
 
Registrado: jul 2004
Ubicación: Barcelona - España
Posts: 18.267
Poder: 10
Neftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en bruto
Cita:
Empezado por ixMike
Ahora he puesto la pregunta y la respuesta por separado para si alguien ve el título, que no lo vea sin respuestas.
Esa es una buena costumbre de la cual muchos deberían tomar nota.

Gracias.
__________________
Germán Estévez => Web/Blog
Guía de estilo, Guía alternativa
Utiliza TAG's en tus mensajes.
Contactar con el Clubdelphi

P.D: Más tiempo dedicado a la pregunta=Mejores respuestas.
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
StarTeam, ese desconocido [Gunman] Varios 5 31-01-2007 18:10:54
DLL con nombre desconocido ixMike Varios 2 28-06-2006 11:05:02
Caracter desconocido... Xianto Varios 3 07-01-2005 15:46:08
Es un camino desconocido Oxa78 Varios 11 25-11-2004 09:47:03
Error Desconocido - Ayuda Por Favor LucasArgentino Conexión con bases de datos 1 12-12-2003 12:49:25


La franja horaria es GMT +2. Ahora son las 10:36:46.


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
Copyright 1996-2007 Club Delphi