Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Error al accesar una funcion en una DLL (https://www.clubdelphi.com/foros/showthread.php?t=57634)

FGarcia 23-06-2008 17:01:59

Error al accesar una funcion en una DLL
 
Bueno..es mi primera vez con las DLL.
He creado una DLL con varios procedimientos y funciones hasta el momento me han funcionado bien, sin embargo he declarado algo muy simple y me aparece un error que no tengo idea porque sucede, me explico:

Código Delphi [-]
//esto esta declarado en la DLL
 
function AjustesActuales : string; stdCall;
begin
  Result := 'Com1,9600,8,none,1';                              
end;
 
exports
    AjustesActuales;
 
begin
end.

y lo llamo asi:

Código Delphi [-]
//La declaro en la aplicacion normal

function AjustesActuales: string; external 'ComScale.dll';
 
implementation
{$R *.dfm}
 
//Aqui la llamo desde una aplicacion normal
procedure TForm1.btnMuestraClick(Sender: TObject);
begin
  StatusBar1.Panels[0].Text := AjustesActuales;
end;

y este es el mensaje de error:

Cita:

---------------------------
Debugger Exception Notification
---------------------------
Project UsaComScale.exe raised exception class EAccessViolation with message 'Access violation at address 00374A08 in module 'ComScale.dll'. Write of address 0042AF9C'. Process stopped. Use Step or Run to continue.
---------------------------
OK Help
---------------------------
Agradesco su ayuda.

Ñuño Martínez 23-06-2008 17:10:54

Creo que olvidaste poner el "StdCall" en la "aplicaión normal". Así que cuando lo llamas no recibe los parámetros de la forma que espera, lo que se traduce en el error.

FGarcia 23-06-2008 17:28:29

ok, bueno la he redeclarado asi:

Código Delphi [-]
function AjustesActuales: string; stdcall; external 'ComScale.dll';

y ahora si la ejecuto solamente a ella y cierro el formulario todo bien.
Si ejecuto ademas otra funcion de la dll al cerrar el formulario me aparece este error:

Cita:

---------------------------
Debugger Exception Notification
---------------------------
Project UsaComScale.exe raised exception class EInvalidPointer with message 'Invalid pointer operation'. Process stopped. Use Step or Run to continue.
---------------------------
OK Help
---------------------------

Gracias nuevamente por la ayuda.

dec 23-06-2008 17:36:04

Hola,

Ignoro si es por eso, pero, me parece que no puedes usar "strings" como parámetros ni como resultados, sino es añadiendo una determinada "unidad" de Delphi, de cuyo nombre no puedo acordarme ahora. El caso es que podrías probar algo como esto:

Código Delphi [-]
function AjustesActuales : PChar; stdCall;
begin
  Result := 'Com1,9600,8,none,1';                              
end;

Y:

Código Delphi [-]
function AjustesActuales: PChar; stdcall; external 'ComScale.dll';

cHackAll 23-06-2008 17:42:36

Error común.

FGarcia 23-06-2008 18:18:58

Ok, anotado y comprobado, no usar string sino PChar.............pero.........
ya con el codigo que realmente debe de ir (el resultado es una cadena identica a la que anteriormente mostre)

Código Delphi [-]
function AjustesActuales : PChar; stdCall;
begin
  Result := PuertoS.Port + ',' + BaudRatetoStr(PuertoS.BaudRate) + ',' +
                                DataBitsToStr(PuertoS.DataBits) + ',' +
                                ParityToStr(PuertoS.Parity.Bits) + ',' +
                                StopBitstoStr(PuertoS.StopBits);
end;

PuertoS es una instancia de un Componente (TComPort) el cual ya fue creado (dinamicamente) antes de llamar a esta funcion. al compilar la dll me dice que son tipos incompatibles string y PChar ¿y 'ora?

dec 23-06-2008 18:23:31

Hola,

Algo como esto, quizás:

Código Delphi [-]
function AjustesActuales : PChar; stdCall;
begin
  Result := PChar(PuertoS.Port + ',' + BaudRatetoStr(PuertoS.BaudRate) + ',' +
                                DataBitsToStr(PuertoS.DataBits) + ',' +
                                ParityToStr(PuertoS.Parity.Bits) + ',' +
                                StopBitstoStr(PuertoS.StopBits));
end;

FGarcia 23-06-2008 18:30:47

Ya lo sabia Dec!!

Solo estaba poniendo a prueba tus conocimientos....:D:D:D

Gracias ya funciono.....amenazo con regresar

FGarcia 23-06-2008 19:50:54

Lo prometido es deuda ¡ya regrese!

Si uso TcomPort como un componente dentro de un form ("soltado" desde la paleta) y quisiera guardar su configuracion lo haria asi:

Código Delphi [-]
procedure TForm1.Button5Click(Sender: TObject);
var
  Archivo: string;
begin
  Archivo := ExtractFilePath(ParamStr(0)) + 'CommCfg.ini';
  
  //Esto es un metodo del componente
  ComPort1.StoreSettings(stIniFile, Archivo);
end;

Ahora como estoy jugando con la DLL he declarado esto:

Código Delphi [-]
//DLL
procedure GuardarConfiguracion(archivo: PChar); stdCall;
begin
  PuertoS.StoreSettings(stIniFile, Archivo);
end;
 
exports
    AjustesActuales,
    GuardarConfiguracion;

y lo llamo asi:

Código Delphi [-]
procedure GuardarConfiguracion(archivo: PChar); stdcall; external 'ComScale.dll';
 
procedure TForm1.Button5Click(Sender: TObject);
var
  Archivo: string;
begin
  Archivo := ExtractFilePath(ParamStr(0)) + 'CommCfg.ini';
  GuardarConfiguracion(pchar(Archivo));
end;

el error que me manda

Cita:

---------------------------
Debugger Exception Notification
---------------------------
Project UsaComScale.exe raised exception class EComPort with message 'Failed to store settings'. Process stopped. Use Step or Run to continue.
---------------------------
OK Help
---------------------------
A mi entender el problema estaria en que la funcion en la dll el parametro Archivo se recibe como un PChar y deberia ser un string (en esencia son lo mismo ¿o no?) luego entonces ¿hace falta una conversion mas? ¿como se haria?

¡Esa si no me la se DEC!

Gracias por la ayuda y disculpas por ser tan pesado.

dec 23-06-2008 19:56:01

Hola,

En este caso la excepción la produce el propio componente "ComPort". No sé. Yo empezaría por ver exactamente dónde "levanta" dicha excepción el componente, a ver qué está pasando ahí: igual no existe el archivo u otra cosa. Si tienes el código fuente de l componente "ComPort" busca entre sus unidades la cadena "Failed to store settings", o el tipo de excepción "EComPort", y a ver qué ves por ahí. Yo empezaría así, vamos... ;)

Io 23-06-2008 20:18:44

Cita:

Empezado por FGarcia (Mensaje 295544)
A mi entender el problema estaria en que la funcion en la dll el parametro Archivo se recibe como un PChar y deberia ser un string (en esencia son lo mismo ¿o no?) luego entonces ¿hace falta una conversion mas? ¿como se haria?

Hola.
Un Pchar no es lo mismo que un string.

Pchar es un puntero a una cadena de caracteres, y la información de la cadena comenzaria en la direción de memoria a la que apunta. Terminando que la información con el caracter nulo. (Cuantas veces se me ha colgado por olvidarme este fin de cadena).

Un string, utiliza el primer byte(cuando lo estudie hace tiempo) para guardar la longitud de la cadena, y la información biene despues.

En delphi existen funciones para pasar dse pchar a string y viceversa.

Hace tiempo estuve practicando, algo parecido, y creo que mi solución fue:
Reservar memoria: Longitud cadena + 1(Fin de cadena), utilizando un pchar para guardar la información. Llamar a la función de la dll, y esta despues de tomar la información libere la memoria.

La verdad que hace tiempo de esto pero creo que me funciono.

Espero no haber liado mucho.

Saludos.

FGarcia 23-06-2008 22:24:59

continuo en lo mismo...
Si vi el error de que lo genera el componente... supongo entonces que el problema estriba en la creacion del componente. Algo falta.

revise el codigo del componente y encontre que :

Código Delphi [-]
TComPort = class(TCustomComPort)

y que :

Código Delphi [-]
// create component
constructor TCustomComPort.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  // component cannot reside on inheritable forms
  FComponentStyle := FComponentStyle - [csInheritable];
  FLinks := TList.Create;
  FTriggersOnRxChar := True;
  FEventThreadPriority := tpNormal;
  FBaudRate := br9600;
  FCustomBaudRate := 9600;
  FPort := 'COM1';
  FStopBits := sbOneStopBit;
  FDataBits := dbEight;
  FEvents := [evRxChar, evTxEmpty, evRxFlag, evRing, evBreak,
             evCTS, evDSR, evError, evRLSD, evRx80Full];
  FHandle := INVALID_HANDLE_VALUE;
  FStoredProps := [spBasic];
  FParity := TComParity.Create;
  FParity.SetComPort(Self);
  FFlowControl := TComFlowControl.Create;
  FFlowControl.SetComPort(Self);
  FTimeouts := TComTimeouts.Create;
  FTimeouts.SetComPort(Self);
  FBuffer := TComBuffer.Create;
  FBuffer.SetComPort(Self);
end;

siguiendo, yo creo en la dll :

Código Delphi [-]
PuertoS := TComPort.Create(Application);
    PuertoS.Port := 'Com1';
    PuertoS.BaudRate := br9600;
    PuertoS.Parity.Bits  := prNone;
    PuertoS.StopBits := sbOneStopBit;
    PuertoS.DataBits := dbEight;
    PuertoS.Events := [evRxChar, evTxEmpty, evRxFlag, evRing, evBreak, evCTS, evDSR, evError, evRLSD, evRx80Full];
    PuertoS.StoredProps := [spBasic];
    PuertoS.FlowControl.OutCTSFlow := False;
    PuertoS.FlowControl.OutDSRFlow := False;
    PuertoS.FlowControl.ControlDTR := dtrDisable;
    PuertoS.FlowControl.ControlRTS := rtsDisable;
    PuertoS.FlowControl.XonXoffOut := False;
    PuertoS.FlowControl.XonXoffIn := False;

La pregunta para los que tengan la paciencia de revisar tantas lineas ¿es correcto como estoy creando el componente?

Reitero mi agradecimiento a la ayuda que puedan prestar.


P.d. Gracias Io por la explicacion de Pchar y Sting.


La franja horaria es GMT +2. Ahora son las 19:41:14.

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