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-09-2018
Avatar de Maniches
Maniches Maniches is offline
Miembro
 
Registrado: nov 2012
Ubicación: Lima - Perú
Posts: 67
Poder: 12
Maniches Va por buen camino
Thumbs up Error Parámetro Referencia componente ActiveX

Hola Amigos del Foro,

Actualmente tengo un problema usando un componente ActiveX que esta devolviendo un parámetro por referencia de tipo WideString(Es la definición de la importación del componente).
Al momento de usar la funcion y pasar un parametro de tipo WideString me esta mostrando el error: "Access violations at address 1381O7AO in module *.DLL. Write of address 00000000"

La definición de la función es:

Código Delphi [-]
    function  ReadInformation(var szCard: WideString; iTimeChip: SYSINT; iTimeMag: SYSINT; iType: SYSINT; const messMag: WideString): SYSINT; safecall;

La definición Exacta según el que ha creado el componente:

HRESULT ReadInformation([in] BSTR* szCard, [in] int iTimeChip, [in] int iTimeMag, [in] int iType, [in] BSTR messMag, [out, retval] int *rc)


Yo estoy haciendo una simple prueba de la función:

Código Delphi [-]
procedure TForm2.btnConInfClick(Sender: TObject);
var
  ....
  CardInformation : WideString;
begin
  try
    ...
    ReadCardResult:= MyCompActX.ReadInformation(CardInformation, 20, 20, 1, 'INGRESE NUM...');
    if Trim(CardInformation) <> '' then
      ShowMessage(CardInformation);
  finally
    MyCompActX.Free;
  end;
end;

Si algún compañero del foro me puede ayudar, por que se esta generando ese problema o la forma de como debe de pasarse un parámetro por referencia a un ActiveX?
La persona que creo el componente me indico trabajarlo con puntero y que a este tengo que asignarle memoria (memoria dinámica). Si pudieran indicarme como es la definición o un ejemplo de lo que me han indicado.

Muchas Gracias a los que me pudieran compartir alguna solución para probar o es problema del componente ActiveX. según el que desarrollo este componente con un app. en visual basic le trabaja muy bien.
__________________
Maniches
maniches@outlook.com

Última edición por Maniches fecha: 17-09-2018 a las 19:32:10.
Responder Con Cita
  #2  
Antiguo 17-09-2018
Avatar de duilioisola
[duilioisola] duilioisola is offline
Miembro Premium
 
Registrado: ago 2007
Ubicación: Barcelona, España
Posts: 1.732
Poder: 20
duilioisola Es un diamante en brutoduilioisola Es un diamante en brutoduilioisola Es un diamante en bruto
Supongo que CartInformation es donde el componente ActiveX devuelve información.
En ese caso, deberás reservar memoria suficiente (Seguramente el manual te informará de la máxima longitud).
Si no sabes este dato, toma un valor que consideres suficiente como para ir un poco sobrado.
El tipo de puntero debería ser PWideChar.
Recuerda que en muchos casos conviene poner todo en un try..finally para asegurarte de que liberas la memoria, pase lo que pase.

Te dejo un ejemplo que llama a una función de Windows para obtener la carpeta temporal.
Código Delphi [-]
function DameTempPath: string;
var
  pcadena : PChar;
begin
  // MAX_PATH está definido en Windows y tiene el valor 260.
  // Reservo 260 bytes de memoria y apunto con pcadena
  GetMem(pcadena, MAX_PATH + 1);

  // Llamo a la función que me devolverá la información en la memoria apuntada por pcadena
  GetTempPath(MAX_PATH, pcadena);

  // Convierto "cadena terminada con null" en "cadena pascal"
  Result := StrPas(pcadena);

  // Libero la memoria
  FreeMem(pcadena);
end;
Responder Con Cita
  #3  
Antiguo 17-09-2018
Avatar de duilioisola
[duilioisola] duilioisola is offline
Miembro Premium
 
Registrado: ago 2007
Ubicación: Barcelona, España
Posts: 1.732
Poder: 20
duilioisola Es un diamante en brutoduilioisola Es un diamante en brutoduilioisola Es un diamante en bruto
Código Delphi [-]
var
  CardInformation : WideString;
  pCardInformation : pWideChar;
...
    // Reservo memoria suficiente para la información a leer (255 caracteres "Wide". 2 bytes por caracter).
    GetMem(pCardInformation, 255 * 2);
    try
      ReadCardResult:= MyCompActX.ReadInformation(pCardInformation, 20, 20, 1, 'INGRESE NUM...');
      // Convierto a cadena pascal
      CardInformation := pWideChar(pCardInformation);
    finally
      FreeMem(pCardInformation);
    end;
...
Responder Con Cita
  #4  
Antiguo 17-09-2018
Avatar de Maniches
Maniches Maniches is offline
Miembro
 
Registrado: nov 2012
Ubicación: Lima - Perú
Posts: 67
Poder: 12
Maniches Va por buen camino
Smile

Gracias Amigo duilioisola
por tu pronta respuesta.

Si ves el post inicial lo volví a actualizar ya que me enviaron la definición de la función.

Voy hacer una prueba en base a tu ejemplo y a ver si me funciona. Yo soy nuevo en este tipo de manejo de componentes ActiveX. si me funciona bien publico la solución para algún amigo que lo necesite.

Si tienes alguna otra sugerencia en base a como esta definido la función te lo agradecería.

Saludos y un abrazo a la distancia.
__________________
Maniches
maniches@outlook.com
Responder Con Cita
  #5  
Antiguo 17-09-2018
Avatar de Maniches
Maniches Maniches is offline
Miembro
 
Registrado: nov 2012
Ubicación: Lima - Perú
Posts: 67
Poder: 12
Maniches Va por buen camino
Lightbulb

Gracias Amigo duilioisola
sinceramente muchas gracias por tu tiempo en responder y por tu ayuda.

he realizado el cambio en base a tu ejemplo que me sugieres y me sale estos errores:

[dcc32 Error] Unit2.pas(38): E2033 Types of actual and formal var parameters must be identical
[dcc32 Error] Unit2.pas(39): E2010 Incompatible types: 'WideString' and 'PWideString'
[dcc32 Error] Unit2.pas(43): E2017 Pointer type required

intente cambiar al tipo de dato PWIDESTRING y me sale los mismos mensajes de error.

habría que cambiar la definición de la función cuando se importo el componente? (*Lib_TLB.pas) o algún otra sugerencia?
__________________
Maniches
maniches@outlook.com
Responder Con Cita
  #6  
Antiguo 17-09-2018
Avatar de Maniches
Maniches Maniches is offline
Miembro
 
Registrado: nov 2012
Ubicación: Lima - Perú
Posts: 67
Poder: 12
Maniches Va por buen camino
Lightbulb

Amigo duilioisola
He intentado modificar la forma de usar la función en base a lo que sugeriste y si bien me compila y ya no me muestra error no puedo obtener la información del parámetro:

Código Delphi [-]
var
  CardInformation : WideString;
  CardInformation2 : ^WideString;
begin
  try
    try
      GetMem(CardInformation2, 255 * 2);
      ReadCardResult:= MyCompActX.ReadInformation(CardInformation2^, 20, 20, 1, 'INGRESE NUM...');
      CardInformation := WideChar(CardInformation2);
      ShowMessage(CardInformation);
      CardInformation := PWideChar(CardInformation2);
      ShowMessage(CardInformation);
      CardInformation := StrPas(PAnsiChar(CardInformation2));
      ShowMessage(CardInformation);
    finally
      FreeMem(CardInformation2);
    end;
    if Trim(CardInformation2) <> '' then
      ShowMessage(CardInformation);
  finally
    MyCompActX.Free;
  end;

La información que debe devolver es: '092261779...' pero revisando el valor que se asigna como resultados de la función es:

CardInformation := WideChar(CardInformation2) --> #$1A30
CardInformation := PWideChar(CardInformation2) --> 'Ұ'#2
CardInformation := StrPas(PAnsiChar(CardInformation2)) --> '°'#4#2

que sugerencias amigo por donde puede estar el problema?
__________________
Maniches
maniches@outlook.com
Responder Con Cita
  #7  
Antiguo 18-09-2018
Avatar de duilioisola
[duilioisola] duilioisola is offline
Miembro Premium
 
Registrado: ago 2007
Ubicación: Barcelona, España
Posts: 1.732
Poder: 20
duilioisola Es un diamante en brutoduilioisola Es un diamante en brutoduilioisola Es un diamante en bruto
Creo que te sobra un ^.

Código Delphi [-]
var
  CardInformation : WideString;
  CardInformation2 : ^WideString; // Puntero a un WideString
begin
  try
    try
      // 1) Reservo 255x2 bytes de memoria a partir de la pisición de CartInformation2
      GetMem(CardInformation2, 255 * 2);
      // 2) Le paso el contenido de CartInformatio2. Es una posición de memoria. NO LE PASO EL CONTENIDO DE LO QUE HAY EN LA POSICION DE MEMORIA
      ReadCardResult:= MyCompActX.ReadInformation(CardInformation2, 20, 20, 1, 'INGRESE NUM...');
      3) // TypeCast para convertir la información recibida que se encuentra a partir de la posicion de memoria CartInformatio2 hasta que encuentre un \n
      CardInformation := WideChar(CardInformation2);
    finally
      // 4) Libreo memoria
      FreeMem(CardInformation2);
    end;

Código:
1) Reservo Memoria
GetMem me devuelve que en la posición 10000 hay un bloque continuo de 255x2 bytes reservados para mi
CartInformatio2 = 10000
CartInformatio2^ = 'B_A%S(U R-A.......'
En la posición de memoria 10000 hay basura (restos de cosas que el ordenador haya procesado)

2) Le paso la posición al componente ActiveX
Esta función rellena a partir de la posición recibida los datos que quiere devolver, terminando con un \n
CartInformatio2 = 10000
CartInformatio2^ = '092261779...\n'

3) Convierto la información recibida en algo mas ameno para trabajar en Delphi

4) Libero memoria
El bloque de 255x2 bytes queda libre para que otro proceso lo pueda utilizar.
Lo que haya en la posicion 10000 en adelante se considera basura para el próximo proceso que utilice.
Responder Con Cita
  #8  
Antiguo 18-09-2018
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.021
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Cita:
Empezado por duilioisola Ver Mensaje
Código:
1) Reservo Memoria
GetMem me devuelve que en la posición 10000 hay un bloque continuo de 255x2 bytes reservados para mi
CartInformatio2 = 10000
CartInformatio2^ = 'B_A%S(U R-A.......'
En la posición de memoria 10000 hay basura (restos de cosas que el ordenador haya procesado)

2) Le paso la posición al componente ActiveX
Esta función rellena a partir de la posición recibida los datos que quiere devolver, terminando con un \n
CartInformatio2 = 10000
CartInformatio2^ = '092261779...\n'

3) Convierto la información recibida en algo mas ameno para trabajar en Delphi

4) Libero memoria
El bloque de 255x2 bytes queda libre para que otro proceso lo pueda utilizar.
Lo que haya en la posicion 10000 en adelante se considera basura para el próximo proceso que utilice.
Estas cosas la mayoría de los nuevos no llegan a entenderlo nunca.
Responder Con Cita
  #9  
Antiguo 18-09-2018
Avatar de Maniches
Maniches Maniches is offline
Miembro
 
Registrado: nov 2012
Ubicación: Lima - Perú
Posts: 67
Poder: 12
Maniches Va por buen camino
Smile

Amigo duilioisola
Nuevamente muchas gracias por tu tiempo y por la disponibilidad en ayudar.
Aquí comparto como me ha funcionado el procedimiento y como he podido obtener la información, claro también agrego unas consultas mas como para cerrar el ciclo de este POST.

Código Delphi [-]
procedure TForm2.btnConInfClick(Sender: TObject);
var
  CardInformation : ^WideString;
  CardInformation2 : WideString;
begin
  try
  ...
    try
      GetMem(CardInformation, 255 * 2);
      ReadCardResult:= MyCompActX.ReadInformation(CardInformation^, 20, 20, 1, 'INGRESE NUM...');
      CardInformation2 := PWideChar(CardInformation^);
    finally
      FreeMem(CardInformation);
    end;
    if Trim(CardInformation2) <> '' then
      ShowMessage(CardInformation2);
  finally
    MyCompActX.Free;
  end;
end;

OBS: Según tu sugerencia de que quizás estaba sobrando "^" no fue por ahí la solución ya que al compilar me salia el siguiente error:
"E2033 Types of actual and formal var parameters must be identical"


Aquí agrego unos comentarios y consultas para aclarar si realmente la solución esta trabajando bien:


Según el diseñador del componente el resultado de la función visualmente esta devolviendo: TEditText = '024517750292005301=22092261779080000000F'
con la solución que adjunto lineas arriba me esta devolviendo: CardInformation2 = '02'#$1C'4517750292005301=22092261779080000000F'
Cuando hago la copia del texto del componente TEditText que muestra el resultado de un app que proporciona el creador del componente ActiveX pasa algo estraño:

Si lo pego en un NOTEPAD = '024517750292005301=22092261779080000000F'
Si lo pego en un NOTEPAD++ = '024517750292005301=22092261779080000000F'

Aquí viene mis preguntas:

1. El resultado de la función según la implementacion adjunta estará devolviendo bien la información en la variable: CardInformation2?
2. Hay alguna forma de castear la variable CardInformation2 para que ya no muestre el carácter "#$1C"?
3. comparando el resultado de la función vs el TEdittext del App del componente, el carácter: #$1C =  (según nos muestra NotePad++ es un FS)
4. A su experiencia y conocimiento se sabe que la función va a devolver dentro de 45 a 80 caracteres, como se calcula el tamaño de memoria que se tiene que reservar para indicarle a la función GetMem?

Muchas gracias a los que ayudaron con su comentarios y su tiempo en especial a "duilioisola", espero ahí me puedan responder las preguntas para cerrar este POST y quede claro para algún colega que pueda necesitar una solución similar.

Gracias a todos por compartir sus conocimiento y para adelante con el foro es muy recomendable y activo.

Un abrazo a la distancia desde Perú.
__________________
Maniches
maniches@outlook.com
Responder Con Cita
  #10  
Antiguo 20-09-2018
Avatar de Maniches
Maniches Maniches is offline
Miembro
 
Registrado: nov 2012
Ubicación: Lima - Perú
Posts: 67
Poder: 12
Maniches Va por buen camino
Lightbulb Error de acceso y liberación de puntero

Amigos del foro.
Acudo a los amigos a apoyarme al resolver un problema que tengo.

para iniciar el problema me esta ocurriendo cuando usa le versión Delphi 6, ya que la misma codificación en Delphi mas actualizado Delphi Tokyo trabaja todo bien. Yo necesito hacer que esto trabaje en delphi 6 ya que el sistema esta usando esa version.

Hay una función de un componente ActiveX y su definición de la importación del componente es:

Código Delphi [-]
 function  ReadInformation(var szCard: WideString; iTimeChip: SYSINT; iTimeMag: SYSINT; iType: SYSINT; const messMag: WideString): SYSINT; safecall;

yo he creado el siguiente proc que si funciona en la versión Tokyo:

Código Delphi [-]
procedure TForm2.btnConInfClick(Sender: TObject);
var
  CardInformation : ^WideString;
  CardInformation2 : WideString;
begin
  try
    try
      GetMem(CardInformation, 128 * 2);
      ReadCardResult:= MyCompActX.ReadInformation(CardInformation^, 20, 20, 1, 'INGRESE NUM...');
      CardInformation2 := PWideChar(CardInformation^);
      edtCardInform.Text:= CardInformation2;
    finally
      FreeMem(CardInformation);
    end;
    if Trim(edtCardInform.Text) <> '' then
      ShowMessage(edtCardInform.Text);
  finally
    MyCompActX.Free;
  end;
end;

El error que me muestra la linea ( CardInformation2 := PWideChar(CardInformation^) ) es: "Access violation at address 00404A83 in module 'TestCInf.exe'. Read of address 0034001C'"

Por favor necesito que me puedan ayudar a identificar el problema, como les mencionaba esto si funciona en una versión mas reciente de delphi, el componente activex requiere de memoria dinámica y por ello se reserva la memoria y luego se libera. pero en Delphi 6 no me esta permitiendo.

Muchas gracias a los amigos que me puedan responder sugiriendo una solución o compartiendo un ejemplo para poder validar la solución.

de antemano muchas gracias.
__________________
Maniches
maniches@outlook.com
Responder Con Cita
  #11  
Antiguo 20-09-2018
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.021
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
He unido ambos hilos porque es lo mismo
Responder Con Cita
  #12  
Antiguo 20-09-2018
Avatar de Maniches
Maniches Maniches is offline
Miembro
 
Registrado: nov 2012
Ubicación: Lima - Perú
Posts: 67
Poder: 12
Maniches Va por buen camino
Gracias amigo, pero no tienes una idea de lo que puede estar pasando?
__________________
Maniches
maniches@outlook.com
Responder Con Cita
  #13  
Antiguo 20-09-2018
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.021
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
¿Por qué no usas el código que te ha puesto de ejemplo duilioisola?
Responder Con Cita
  #14  
Antiguo 20-09-2018
Avatar de Maniches
Maniches Maniches is offline
Miembro
 
Registrado: nov 2012
Ubicación: Lima - Perú
Posts: 67
Poder: 12
Maniches Va por buen camino
Lightbulb

si quito en carácter que el indica "^"

al compilar me muestra el sgte error: "Types of actual and formal var parameters must be identical"

Código Delphi [-]
      ReadCardResult:= MyCompActX.ReadInformation(CardInformation, 20, 20, 1, 'INGRESE NUM...');
      CardInformation2 := PWideChar(CardInformation);

como mencionaba el ejemplo que publico si me esta funcionando en la versión mas actual. No se porque lo mismo no me funciona en D6.

Gracias por tu ayuda.
__________________
Maniches
maniches@outlook.com
Responder Con Cita
  #15  
Antiguo 21-09-2018
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.021
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Cita:
Empezado por Maniches Ver Mensaje
si quito en carácter que el indica "^"
al compilar me muestra el sgte error: "Types of actual and formal var parameters must be identical"
A ver si es por otro parámetro, porque así a simple vista, diría que el que no debería funcionar es el que has puesto el "^".
Responder Con Cita
  #16  
Antiguo 21-09-2018
Avatar de Maniches
Maniches Maniches is offline
Miembro
 
Registrado: nov 2012
Ubicación: Lima - Perú
Posts: 67
Poder: 12
Maniches Va por buen camino
Casimiro

la definición de la función en el lenguaje que crearon el componente es:

Código:
HRESULT ReadInformation([in] BSTR* szCard, [in] int iTimeChip, [in] int iTimeMag, [in] int iType, [in] BSTR messMag, [out, retval] int *rc)
cuando importe el componente via delphi 6 en el archivo *_TLB.pas:

Código Delphi [-]
function  ReadInformation(var szCard: WideString; iTimeChip: SYSINT; iTimeMag: SYSINT; iType: SYSINT; const messMag: WideString): SYSINT; safecall;

por ello como te decía a la prueba que indico en el post si quito el carácter "^" me muestra error y muy probable por la definición de la importación.

Si bien pude resolver la forma de obtener la información del puntero, la cosa que todo se soluciono en Delphi Tokyo. el problema es que el app que va usar esa función esta trabajando con Delphi 6 y al hacer la misma prueba ahí no me funciona ya que me genera los errores que menciono.

Tienes un ejemplo o otra forma de trabajar las funciones de componentes ActiveX con Memoria Dinamica? actualmente se esta usando ese componente con otras funciones que contiene, la diferencia que la cadena que esta devolviendo lo hace como resultado de la función y estas funciones trabajan normal en D6. pero en esta función que menciono el resultado lo están devolviendo por un parámetro por referencia.
__________________
Maniches
maniches@outlook.com

Última edición por Maniches fecha: 21-09-2018 a las 01:28:58.
Responder Con Cita
  #17  
Antiguo 21-09-2018
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.021
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
¿Y así no funciona en ninguno?

Código Delphi [-]
ReadCardResult:= MyCompActX.ReadInformation(CardInformation, 20, 20, 1, 'INGRESE NUM...');
CardInformation2 := CardInformation^;
Responder Con Cita
  #18  
Antiguo 24-09-2018
Avatar de Maniches
Maniches Maniches is offline
Miembro
 
Registrado: nov 2012
Ubicación: Lima - Perú
Posts: 67
Poder: 12
Maniches Va por buen camino
Hola Casimiro,

No me funciona así como me mencionas ya que me sale error de compilación. mensajes anteriores lo indico.

Mira actualmente ese tema no lo he podido resolver de a primeras ya que el problema parte por la versión de delphi y el SO.

Yo como menciono lineas atrás con una versión delphi mas actual(Tokyo) no genera ese error. el problema es con la versión D6. como esa versión es bastante antigua parece que maneja de otra manera el tema de punteros y/o memoria en windows 10. actualmente del mismo componente se usa de forma similar pero la definición del parámetro como "OUT". pero con la función que generaba el error la crearon con "IN".

En general hice el intento de muchas formas y no pude resolver el error. después de varios días de investigación se solicito que cambien la definición de la función del componente.

Gracias a todos los amigos del foro por sus comentarios.

Saludos.
__________________
Maniches
maniches@outlook.com
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
Como quitar referencia de un componente steelha Varios 7 25-02-2013 16:48:58
Componente ActiveX importardo da error jmlifi OOP 5 03-05-2010 15:04:33
Componente activex levache Internet 6 30-12-2006 06:01:11
Ver componente ActiveX piccolo2101 Varios 1 05-12-2005 10:59:23
Eliminar componente ActiveX Coco_jac Varios 5 08-08-2005 19:43:52


La franja horaria es GMT +2. Ahora son las 22:00:05.


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