Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 11-05-2012
JXJ JXJ is offline
Miembro
 
Registrado: abr 2005
Posts: 2.475
Poder: 22
JXJ Va por buen camino
Question ¿como hacer dll c puro en bcb2010 y loader en delphi 2010?

hola estoy haciendo una dll
en c
c puro, no es cpp o c++
con el ide de c++ builder 2010

y el programa que lo consume esta hecho en delphi 2010

el problema es que no me devuelve lo que yo quiero un string para saber que paso con
las instrucciones

pongo el codigo. de la dll

Código:
// ---------------------------------------------------------------------------
// ES UNA DLL TIPOP C  SIN NINGUN ESTILO NI VCL NI ESTILO VC
// ---------------------------------------------------------------------------

#include <windows.h>
#include <string.h>
#pragma argsused
#include <stdio.h>
#include <stdlib.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>

static char *file2string(FILE *file)
{
  char buffer[256];
  char *ptr;
  char *string=NULL;
  size_t len=0;
  size_t stringlen;

  if(file) {
    while(fgets(buffer, sizeof(buffer), file)) {
      ptr= strchr(buffer, '\r');
      if(ptr)
        *ptr=0;
      ptr= strchr(buffer, '\n');
      if(ptr)
        *ptr=0;
      stringlen=strlen(buffer);
      if(string)
        string = realloc(string, len+stringlen+1);
      else
        string = malloc(stringlen+1);

      strcpy(string+len, buffer);

      len+=stringlen;
    }
    return string;
  }
  else
    return NULL; /* no string */
}

static char *file2memory(FILE *file, long *size)
{
  char buffer[1024];
  char *string=NULL;
  char *newstring=NULL;
  size_t len=0;
  long stringlen=0;

  if(file) {
    while((len = fread(buffer, 1, sizeof(buffer), file))) {
      if(string) {
        newstring = realloc(string, len+stringlen);
        if(newstring)
          string = newstring;
        else
          break; /* no more strings attached! :-) */
      }
      else
        string = malloc(len);
      memcpy(&string[stringlen], buffer, len);
      stringlen+=len;
    }
    *size = stringlen;
    return string;
  }
  else
    return NULL; /* no string */
}


static size_t mywrite(void * ptr , size_t size , size_t nmemb , void * stream){
int ret  = fwrite(ptr,size,nmemb,(FILE *)stream);
fwrite(ptr,size,nmemb,stdout);
return ret;
}



char __declspec(dllexport)WINAPI   suma(char *ELPRIMERPARAMETRO, char *ELSEGUNDOPARAMETRO,
                                      char *ELTERCERPARAMETRO, char *ELCUARTOPARAMETRO)
{

      FILE * header = fopen(ELPRIMERPARAMETRO,"w");
      FILE * body = fopen(ELSEGUNDOPARAMETRO,"w");

 char *TipoResultado;
      TipoResultado = "3333";


   MessageBox( NULL, ELPRIMERPARAMETRO, "1r", MB_OK );
   MessageBox( NULL, ELSEGUNDOPARAMETRO, "2d", MB_OK );
   MessageBox( NULL, ELTERCERPARAMETRO, "3e", MB_OK );
   MessageBox( NULL, ELCUARTOPARAMETRO, "4t", MB_OK );

    return *TipoResultado;
}

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason,
    void* lpReserved)
    {
    return 1;
}
// ---------------------------------------------------------------------------
y este es el de l aaplicacion delphi
Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExceptionLog;

type
    TDLLFunc = function(param1: AnsiString; param2: AnsiString; param3: AnsiString; param4: AnsiString): PAnsiChar;

type
  TForm1 = class(TForm)
    Button1: TButton;
    EurekaLog1: TEurekaLog;
    Edit1: TEdit;
    Edit2: TEdit;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

  { assign a nil - not loaded function }

  {assign a nil - not loaded function}
 const
   DLLFunc: TDLLFunc = nil;
   DLLName = 'inicio.DLL';
 {handle of loaded dll}
 var
  DLLHandle: THandle;

implementation

{$R *.dfm}
function suma(parametro1: AnsiString; parametro2: AnsiString; parametro3 :AnsiString;  parametro4 :AnsiString): PAnsiChar; stdcall; far; external 'inicio.DLL';

procedure TForm1.FormCreate(Sender: TObject);
var
  resultadosuma: PAnsiChar;
  recibido:string;
begin
  DLLHandle := LoadLibrary(DLLName);

  if (DLLHandle < HINSTANCE_ERROR) then
    raise Exception.Create(DLLName + ' library can not be loaded or not found. ' + SysErrorMessage(GetLastError));
  try
    @DLLFunc := GetProcAddress(DLLHandle, 'suma');
    if Assigned(DLLFunc) then
    begin

resultadosuma :=   suma(
                     PansiChar(AnsiString('a1')),
                     PansiChar(AnsiString('b2')),
                     PansiChar(AnsiString('c3')),
                     PansiChar(AnsiString('d4'))
                     );
    end;
  finally
    FreeLibrary(DLLHandle);
  end;

  ShowMessage(  resultadosuma);

end;

end.


logre que se pasen los parametros de delphi a la dll y que me los muestre
el problema es que no me devuelve nada
yo espero un string
3333
y no me vuelve nada

solo me ha funcionado usando integer en vez de string.
en la dll c

en c estoy aprendiendo. y pues no se que hago mal

gracias.


la funcion se llama suma. por que asi se me ocurrio pero debe de regresar un string para procesarlo
Responder Con Cita
  #2  
Antiguo 11-05-2012
LoPiTaL LoPiTaL is offline
Miembro
 
Registrado: abr 2009
Posts: 168
Poder: 16
LoPiTaL Va por buen camino
Hola!
Cuando usas DLLs debes tener cuidado con el paso de parámetros que se crean / destruyen dinámicamente fuera de tu control, esto es, tipos de datos "managed", como por ejemplo strings. El compilador lleva internamente el conteo de las instancias de una string, de tal forma que cuando se deja de referenciar, la destruye automáticamente. Por eso se pueden hacer operaciones tipo 'mistring'+'miotrastring' y ya se encarga el compilador de crear una nueva string donde quepan todos los caracteres, etc...
Sin embargo, cuando trabajas con DLLs, el compilador deja de tener ese control sobre estos tipos de datos, por lo que si se le pasa a una DLL una cadena para que la almacene, y la función que llama deja de referenciar a esta cadena, ésta se destruirá provocando AV en la DLL, que cree que la cadena todavía existe. Es por esto por lo que con enteros te ha funcionado, pero con strings no.

El mismo RAD Studio te da información sobre ésto cuando creas una nueva DLL. En el archivo principal de la DLL te aparece el siguiente comentario:

Código Delphi [-]
{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }

Esto se puede resolver evitando el paso de parámetros de tipo manejado. Esto es, reemplazando parámetros string, AnsiString, etc... por parámetros tipo PChar, PAnsiChar, etc... y en la DLL recrear la string mediante StrPas. De igual forma, el resultado devuelto NO debe ser manejado, por lo que deberías hacer lo mismo, devolver PChar y en la función llamante recrear la string con StrPas.

También se puede evitar si en lugar de DLLs usas BPLs, pero dejas de ser compatible con otros lenguajes.

Por otro lado, veo que no tienes bien definida la cabecera en Delphi. Si usas char * en C, debes usar PAnsiChar en Delphi (por lo que también tendrías resuelto el problema que te comento anteriormente). Y el resultado de la función es char (sin puntero), por lo que el resultado en Delphi deberá ser AnsiChar (sin la P).
Ahh! Y ojo con PChar y PAnsiChar, ya que en Delphi2007+ PChar es Unicode (puede ser 1, 2 ó 4 bytes), mientras que PAnsiChar es el de 1 byte de siempre.

Espero haberte ayudado.

Un saludo,
LoPiTaL
Responder Con Cita
  #3  
Antiguo 11-05-2012
JXJ JXJ is offline
Miembro
 
Registrado: abr 2005
Posts: 2.475
Poder: 22
JXJ Va por buen camino
hola

LoPiTaL

gracias por tu atencion.
aun me queda un problema


una duda sobre la variable que recibe el valor de la dll
arregle asi

Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExceptionLog;

type
    TDLLFunc = function(param1: PAnsiChar ; param2: PAnsiChar ; param3: PAnsiChar ; param4: PAnsiChar ): AnsiChar  ;

type
  TForm1 = class(TForm)
    Button1: TButton;
    EurekaLog1: TEurekaLog;
    Edit1: TEdit;
    Edit2: TEdit;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

  { assign a nil - not loaded function }

  {assign a nil - not loaded function}
 const
   DLLFunc: TDLLFunc = nil;
   DLLName = 'inicio.DLL';
 {handle of loaded dll}
 var
  DLLHandle: THandle;

implementation

{$R *.dfm}
function suma(parametro1: PAnsiChar ; parametro2: PAnsiChar ; parametro3:PAnsiChar ; parametro4:PAnsiChar ): AnsiChar;
              stdcall; far; external 'inicio.DLL';

procedure TForm1.FormCreate(Sender: TObject);
var
  resultadosuma: string;
begin
  DLLHandle := LoadLibrary(DLLName);

  if (DLLHandle < HINSTANCE_ERROR) then
    raise Exception.Create(DLLName + ' library can not be loaded or not found. ' + SysErrorMessage(GetLastError));
  try
    @DLLFunc := GetProcAddress(DLLHandle, 'suma');
    if Assigned(DLLFunc) then
    begin

resultadosuma :=    suma(
                     PansiChar(AnsiString('a1')),
                     PansiChar(AnsiString('b2')),
                     PansiChar(AnsiString('c3')),
                     PansiChar(AnsiString('d4'))
                     );
    end;
  finally
    FreeLibrary(DLLHandle);
  end;

   ShowMessage( ' el resultado es '+ resultadosuma);

end;

end.


Código Delphi [-]
var
  resultadosuma: string;
begin

   ShowMessage( ' el resultado es '+  resultadosuma);
end

en el show message obtengo un 3

y se supone que deberia de ser un 3333

bueno una cadena de cuatro 3

en delphi 2010 no me dejsa usar strpas


que no se puede llamar con esos argumentos
Código Delphi [-]
var
  resultadosuma: string;
begin

   ShowMessage( ' el resultado es '+ StrPas(resultadosuma));
end
Responder Con Cita
  #4  
Antiguo 11-05-2012
LoPiTaL LoPiTaL is offline
Miembro
 
Registrado: abr 2009
Posts: 168
Poder: 16
LoPiTaL Va por buen camino
Hola!
Veo varias cosas mal en tu código, te comento:

Código Delphi [-]
 const
   DLLFunc: TDLLFunc = nil;
   DLLName = 'inicio.DLL';

DLLName sí que es constante. DLLFunc es una variable.... primero apunta a nil, y después a la dirección de la función en la DLL. Por tanto, cámbialo por:

Código Delphi [-]
 var
   DLLFunc: TDLLFunc = nil;
const
   DLLName = 'inicio.DLL';

Segundo, estás liándote con la carga de la DLL. Puedes cargar una DLL de dos formas:
Así, siendo la carga automática (la palabra far te sobra....):
Código Delphi [-]
function suma(parametro1: PAnsiChar ; parametro2: PAnsiChar ; parametro3:PAnsiChar ; parametro4:PAnsiChar ): AnsiChar;
              stdcall; external 'inicio.DLL';

procedure TForm1.FormCreate(Sender: TObject);
var
  resultadosuma: string;
begin
resultadosuma :=    suma(
                     PansiChar(AnsiString('a1')),
                     PansiChar(AnsiString('b2')),
                     PansiChar(AnsiString('c3')),
                     PansiChar(AnsiString('d4'))
                     );
end;
O de esta otra forma, que sería manual:

Código Delphi [-]
procedure TForm1.FormCreate(Sender: TObject);
var
  resultadosuma: string;
begin
  DLLHandle := LoadLibrary(DLLName);

  if (DLLHandle < HINSTANCE_ERROR) then
    raise Exception.Create(DLLName + ' library can not be loaded or not found. ' + SysErrorMessage(GetLastError));
  try
    @DLLFunc := GetProcAddress(DLLHandle, 'suma');
    if Assigned(DLLFunc) then
    begin
//NOTAR QUE LLAMO A LA VARIABLE DLLFUNC, y no a la función que habías definido "suma"
resultadosuma :=    DLLFunc(
                     PansiChar(AnsiString('a1')),
                     PansiChar(AnsiString('b2')),
                     PansiChar(AnsiString('c3')),
                     PansiChar(AnsiString('d4'))
                     );
...
  end;
end;
pero no de las dos formas a la vez!!!

Las dos son igual de válidas, pero si usas la primera, si la librería no existe tu aplicación no arrancará, mietras que si usas la segunda puedes controlar esto y hacer otras cosas, o no usar la funcionalidad que proporciona etc... La más sencilla es la primera, por supuesto.

Tercero:
StrPas recibe un PChar (o PAnsiChar) como parámetro y devuelve un string. Por supuesto no puedes hacer StrPas(resultadosuma), ya que resultadosuma es string, no PAnsiChar. Para usarlo bien deberás usarlo así:

Código Delphi [-]
var
  LStringAMostrar: string;
begin
  LStringAMostrar:=StrPas(suma(...));  //Tal como tienes el código ahora te dará error. Sigue en punto cuatro...
end

Cuarto:
Si quieres que suma devuelve una cadena de texto, NOOOOO puede devolver AnsiChar, ya que AnsiChar es un carácter sólo!!! Deberá devolver un PAnsiChar, exactamente igual que lo harías en c. Ahora tendrás un puntero a una cadena, el cual puedes pasarle a StrPas para que te genere la string correcta.

Creo que eso es todo....

Un saludo,
LoPiTaL
Responder Con Cita
Respuesta



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
Como instalo ZeosLib en Delphi 2010 jorosmtz Conexión con bases de datos 21 21-08-2012 00:48:46
delphi 2010 imagenes png¿como usarlas? JXJ Varios 2 13-09-2010 21:40:49
Hacer que Delphi 2010 luzca como Delphi 7 jorosmtz La Taberna 0 11-04-2010 22:45:36
¿cómo hacer un reporte con ravereport de delphi 2010 o un manual ? Master23 Impresión 1 06-04-2010 16:43:20
Iniciar un Loader REHome .NET 5 24-12-2008 10:24:29


La franja horaria es GMT +2. Ahora son las 11:36:35.


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