delphi dll vb6 typelib

Probar DLL de Delphi bloquea VB6 IDE



typelib (5)

He tenido mi primer intento al escribir una DLL en Delphi. Hasta aquí todo bien. Al usar un typelib, he podido pasar Widestrings desde y hacia el DLL sin dificultad.

Lo que es curioso en este momento es que estoy usando VB6 como banco de pruebas, y cada vez que ejecuto una prueba dentro del IDE, el programa se ejecuta y luego el proceso IDE desaparece repentinamente de la memoria, sin mensajes de error, nada. Si paso por el código, todo funciona bien hasta que ejecute la última línea, entonces el IDE desaparece.

Por el contrario, cuando compilo la prueba en un EXE, el programa corre hasta su final, sin mensajes de error, etc.

¿Alguien ha tenido este problema antes y hay una solución obvia que me está mirando a la cara?

Código fuente a continuación, en caso de que importe:

- proyecto

library BOSLAD; uses ShareMem, SysUtils, Classes, BOSLADCode in ''BOSLADCode.pas''; exports version, DMesg, foo; {$R *.res} begin end.

- unidad

unit BOSLADCode; interface function version() : Double; stdcall; procedure DMesg(sText : WideString; sHead : WideString ); stdcall; function foo() : PWideString; stdcall; implementation uses Windows; function version() : Double; var s : String; begin result := 0.001; end; procedure DMesg( sText : WideString; sHead : WideString); begin Windows.MessageBoxW(0, PWideChar(sText), PWideChar(sHead), 0); end; function foo() : PWideString; var s : WideString; begin s := ''My dog''''s got fleas''; result := PWideString(s); end; end.

- typelib

// This is the type library for BOSLAD.dll [ // Use GUIDGEN.EXE to create the UUID that uniquely identifies // this library on the user''s system. NOTE: This must be done!! uuid(0C55D7DA-0840-40c0-B77C-DC72BE9D109E), // This helpstring defines how the library will appear in the // References dialog of VB. helpstring("BOSLAD TypeLib"), // Assume standard English locale. lcid(0x0409), // Assign a version number to keep track of changes. version(1.0) ] library BOSLAD { // Now define the module that will "declare" your C functions. [ helpstring("Functions in BOSLAD.DLL"), version(1.0), // Give the name of your DLL here. dllname("BOSLAD.dll") ] module BOSLADFunctions { [helpstring("version"), entry("version")] void __stdcall version( [out,retval] double* res ); [helpstring("DMesg"), entry("DMesg")] void __stdcall DMesg( [in] BSTR msg, [in] BSTR head ); [helpstring("foo"), entry("foo")] void __stdcall foo( [out,retval] BSTR* msg ); } // End of Module }; // End of Library

Moví la declaración de WideString fuera de la función en la que lo había declarado, con la expectativa de que eso aumentaría la vida útil de la variable a más tiempo que solo la duración de la función foo . No hizo ninguna diferencia en absoluto.

Del mismo modo comenté fuera de la VB6 la llamada a la función foo . Eso tampoco hizo ninguna diferencia. No importa lo que haga, VB6 IDE muere después de que se ejecuta la última línea de código.

La causa es algo aparte de los indicadores de las variables locales. ¿Pero que?


Para explicar la respuesta de GSerg:

result := PWideString(s);

uno pensaría que estaría bien porque s se inicializó con un literal de cadena ... pero las cadenas anchas en Delphi no son contadas como cadenas normales, por lo que en realidad contienen un poco de memoria dinámica asignada, y tan pronto como la función devuelve esta memoria se puede reutilizar :(

Lo siguiente debería estar bien, aunque:

function foo() : PWideString; const s : WideString = ''My dog''''s got fleas''; begin result := PWideString(s); end;


Crear archivos DLL en el sitio delphi.wikia.com tiene la respuesta que estaba buscando. Y la solución también.

Por ejemplo, Delphi asigna y libera automáticamente la memoria para almacenar sus cadenas, sabe cuándo ya no se necesitan, etc. Lo mismo se aplica, por ejemplo, a Visual Basic, pero ambos lo hacen de diferentes maneras. Por lo tanto, si transfiriera una cadena asignada por Visual Basic a un archivo DLL escrito en Delphi, terminaría en un gran problema, ya que ambos intentarían administrar la cadena y se pelearían entre ellos.

¡La solución es usar FastMM y funciona de manera brillante! Ahora tengo un BORLNDMM.DLL reemplazo con mi proyecto y todo funciona.


result := PWideString(s);

Está devolviendo el puntero a una variable local aquí. Inmediatamente se vuelve inválido.


Acabo de enderezarlo por completo, gracias a Rob Kennedy en las noticias: comp.lang.pascal.delphi.misc

Él dijo, entre otras cosas que:

  1. Esta DLL no necesita ShareMem, SysUtils o Classes.
  2. Has tomado una WideString y le has dicho al compilador que realmente es un puntero a WideString. Estás mintiendo al compilador. No le importa, pero la persona que llama de esta función probablemente sí.

Por lo tanto, el código revisado, que funciona bien sin ShareMem (y SysUtils y Classes que fueron agregados por el Asistente para DLL como sucede) es el siguiente:

library BOSLAD; uses BOSLADCode in ''BOSLADCode.pas''; exports version, DMesg, foo; {$R *.res} begin end.

BOSLADCode.pas:

unit BOSLADCode; interface function version() : Double; stdcall; procedure DMesg(sText : PWideChar; sHead : PWideChar ); stdcall; function foo() : PWideChar; stdcall; implementation uses Windows; var s : WideString; function version() : Double; begin result := 0.001; end; procedure DMesg( sText : PWideChar; sHead : PWideChar); begin Windows.MessageBoxW(0, sText, sHead, 0); end; function foo() : PWideChar; begin s := ''My dog''''s got fleas''; result := PWideChar(s); end; end.

boslad.odl:

// This is the type library for BOSLAD.dll [ uuid(0C55D7DA-0840-40c0-B77C-DC72BE9D109E), helpstring("BOSLAD TypeLib"), lcid(0x0409), version(1.0) ] library BOSLAD { [ helpstring("Functions in BOSLAD.DLL"), version(1.0), dllname("BOSLAD.dll") ] module BOSLADFunctions { [helpstring("version"), entry("version")] void __stdcall version( [out,retval] double* res ); [helpstring("DMesg"), entry("DMesg")] void __stdcall DMesg( [in] BSTR msg, [in] BSTR head ); [helpstring("foo"), entry("foo")] void __stdcall foo( [out,retval] BSTR* msg ); } };

test.bas:

Sub Main() Dim cfg As New CFGProject.cfg cfg.Load "test.cfg" Dim s As String s = cfg.Recall("msg") DMesg s, "" & version s = foo DMesg s, "" & version End Sub

test.cfg

msg=毅訜訝

Todo eso funciona perfectamente. IDE de VB6 ejecuta felizmente el DLL y los MsgBoxs aparecen con todo como deberían.


Creo que podemos cerrar este. El código siguiente parece ser suficiente para mantener al público news:comp.lang.pascal.delphi.misc feliz y realmente necesito pasar de la prueba conceptual a hacer algo con ella.

BOSLAD.bdsproj:

library BOSLAD; uses BOSLADCode in ''BOSLADCode.pas''; exports version, DMesg, foo; {$R *.res} begin end.

BOSLADCode.pas:

unit BOSLADCode; interface function version() : Double; stdcall; procedure DMesg(const sText : WideString; const sHead : WideString ); stdcall; function foo() : PWideChar; stdcall; implementation uses Windows, ActiveX; function version() : Double; begin result := 0.001; end; procedure DMesg( const sText : WideString; const sHead : WideString); begin Windows.MessageBoxW(0, PWideChar(sText), PWideChar(sHead), 0); end; function foo() : PWideChar; var s : WideString; begin s := ''My dog''''s got fleas''; result := SysAllocString(PWideChar(s)); end; end.

Ahora VB está contento y no tengo bloqueos IDE raros.