Utilizamos cookies propias y de terceros. [Más información sobre las cookies].
Política de cookies
Proyecto AjpdSoft

· Inicio
· Buscar
· Contactar
· Cookies
· Descargas
· Foros
· Historia
· Nosotros
· Temas
· Top 10
· Trucos
· Tutoriales
· Wiki
Proyecto AjpdSoft: Foros

AjpdSoft :: Ver tema - Error en dll y delphi 'Operación de puntero no válida'
Foros de discusión Buscar Perfil FAQ Iniciar sesión
Information Error en dll y delphi 'Operación de puntero no válida'

Publicar nuevo tema Responder al tema
Foros de discusión » Borland Delphi, Codegear Delphi .Net   
Ver tema anterior :: Ver tema siguiente
AutorMensaje
varios
Magnífico usuario


Registrado: Oct 10, 2006
Mensajes: 2092

Asunto: Error en dll y delphi 'Operación de puntero no válida' Responder citando

Estoy realizando una dll en delphi, siguiendo los pasos del manual que tenéis en vuestra web, cuando intento hacer la llamada a un procedimiento de la dll, se ejecuta una vez correctamente pero me da este error:

"Operación de puntero no válida"

lo raro del tema es que si intento llamarla una segunda vez empieza a dar errores de todo tipo "violación de acceso" y demás. La función se llega a ejecutar, incluso devuelve los valores correctos, pero siempre me aparece este error.

Este es el código fuente completo de la dll que he realizado:

Código:

library milibreria;

uses
  SysUtils,
  Classes, db, NCOciDB, NCOci, NCOciWrapper;

function consultaBD (numExpediente : string; var nombreCompleto : string;
    var DNI : string; var fechaCaducidad : string; var telefono : string;
    var direccion : string; var municipio : string; var codigoPostal : string;
    var tipoTarifa : string) : boolean; stdcall;
var
  bdConexion : TOCIDatabase;
  tcConsulta : TOCIQuery;
begin
  nombreCompleto := '';
  //... quito inicialización para abreviar

  bdConexion := TOCIDatabase.Create(nil);
  bdConexion.ServerName := 'SERVIDOR';
  bdConexion.UserName := 'usuario';
  bdConexion.Password := 'contraseña';
  bdConexion.LoginPrompt := false;
  bdConexion.ConnectString := bdConexion.UserName + '/' +  bdConexion.Password +
      '@' + bdConexion.ServerName;
  bdConexion.Connected := true;
  tcConsulta := TOCIQuery.Create(nil);
  tcConsulta.ReadOnly := true;
  tcConsulta.Close;
  tcConsulta.SQL.Clear;
  tcConsulta.SQL.Add('SELECT tcp.FINALREF NumExp, tcp.MANAME NombreCompleto, tcp.MAIDNUMBER DNINum,');
  //... quito sql para abreviar
  tcConsulta.SQL.Add('  and tcp.FINALREF=:pNumExp');
  tcConsulta.ParamByName('pNumExp').DataType := ftString;
  tcConsulta.ParamByName('pNumExp').AsString := numExpediente;
  tcConsulta.open;
  if tcConsulta.RecordCount > 0 then
  begin
    nombreCompleto := tcConsulta.fieldbyname('NombreCompleto').AsString;
    //... quito código para abreviar
    Result := true;
  end
  else
    Result := false;
end;

exports consultaBD;

{$R *.res}

begin
end.


La aplicación que utilizo para llamar la dll es la siguiente:

Código:

unit UnidadMenuPrincipal;

interface

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

type
  TformMenuPrincipal = class(TForm)
    bMostrar: TButton;
    txtNumExp: TEdit;
    Label1: TLabel;
    meDatos: TMemo;
    procedure bMostrarClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  formMenuPrincipal: TformMenuPrincipal;

function consultaBD (numExpediente : String; var nombreCompleto : String;
    var DNI : String; var fechaCaducidad : String; var telefono : String;
    var direccion : String; var municipio : String; var codigoPostal : String;
    var tipoTarifa : String) : boolean; stdcall; external 'milibreria.dll';

implementation

{$R *.dfm}


procedure TformMenuPrincipal.bMostrarClick(Sender: TObject);
var
  nombreCompleto, DNI, municipio, codigoPostal, fechaCaducidad,
  tipoTarifa, telefono, direccion  : String;
begin
  meDatos.Lines.Clear;
  if consultaBD (txtNumExp.Text, nombreCompleto, DNI, fechaCaducidad, telefono,
      direccion, municipio, codigoPostal, tipoTarifa) then
  begin
    meDatos.Lines.Add(nombreCompleto);
    meDatos.Lines.Add(DNI);
    meDatos.Lines.Add(fechaCaducidad);
    meDatos.Lines.Add(telefono);
    meDatos.Lines.Add(direccion);
    meDatos.Lines.Add(municipio);
    meDatos.Lines.Add(codigoPostal);
    meDatos.Lines.Add(tipoTarifa);
  end
  else
    showmessage ('No existe el expediente.');
end;

end.



Cuando pulso el botón "bMostrar" y se ejecuta el procedimiento "bMostrarClick" es cuando se produce el error de "Operación de puntero no válida", a veces hasta se cierra la aplicación que hace la llamada a la dll.
MensajePublicado:
Mar Feb 13, 2007 10:42 am
Top of PageVer perfil de usuario
alonsojpd
Administrador/Moderador


Registrado: Sep 16, 2003
Mensajes: 2687

Asunto: Re: Error en dll y delphi 'Operación de puntero no válida' Responder citando



Anuncios



Efectivamente, cuando se crea una dll (librería) con Delphi, nos muestra este mensaje:

{ 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. }


indicando que para trabajar con funciones que utilicen como parámetros tipos de datos string, incluso si se utilizan dentro de estructuras de tipo record, es preciso colocar como primera claúsula del USES de la librería la unidad "ShareMem", la cual gestiona la asignación y liberación de la memoria manualmente. Esto nos obliga a añadir a nuestra dll otra dll de Delphi, la borlndmm.dll, para gestionar el uso de memoria. Obviamente esta tarea puede ser árdua y difícil, por lo que recomendamos, para evitar estas complicaciones, que utilices el tipo de datos ShortString (string de 255 caracteres como máximo), si este tipo de datos no te es suficiente, debes utilizar PChar, que, a todos los efectos, es como un string.

En resumen, para solucionar tu problema es suficiente con que cambies el tipo de datos "String" de todos los parámetros de la función "consultaBD" por ShortString, si no te es suficiente deberás cambiarlos por PChar, aunque este último te suponga algunos pequeños cambios en el código.

En adelante, siempre que utilices una función en una dll que quieras hacer pública con export no es conveniente utilizar el tipo de datos "string" en los parámetros que luego se utilizarán en la llamada a la función pública.
MensajePublicado:
Mar Feb 13, 2007 6:45 pm
Top of PageVer perfil de usuario
Mostrar mensajes de anteriores:   
Todas las horas son GMT - 1 Horas
Publicar nuevo tema Responder al tema
Foros de discusión » Borland Delphi, Codegear Delphi .Net  

Cambiar a:  
Key
  Puede publicar nuevos temas en este foro
No puede responder a temas en este foro
No puede editar sus mensajes en este foro
No puede borrar sus mensajes en este foro
No puede votar en encuestas en este foro
Visita nuestro nuevo sitio web con programas y contenidos actualizados: Proyecto A