Delphi DLL Testing VB6 IDE Fails

I had my first work on writing a DLL in Delphi. So far, so good. Using typelib, I was able to easily pass Widestrings to and from the DLL.

At the moment, it is curious that I use VB6 as a test bench, and every time I run a test in the IDE, the program starts and then the IDE process suddenly disappears from memory - there are no error messages. If I go through the code, everything will work fine until I get the last line, then the IDE will disappear.

In contrast, when I compile a test in EXE, the program ends without error messages, etc.

Has anyone had this problem before and is there an obvious solution that looks in my face?

The source code is below, in case it matters:

- project

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

- unit

 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' 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 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 

I moved the WideString declaration beyond the function in which I declared it, in the expectation that this would increase the lifetime of the variable longer than just the lifetime of the foo function. It didn't make any difference.

Similarly, I commented on the VB6 call to the foo function. It didn't matter either. No matter what I do, the VB6 IDE dies after the last line of code is executed.

Something other than pointers to local variables is the cause. But what?

+4
source share
5 answers

To clarify GSerg's answer:

 result := PWideString(s); 

you would think that it would be ok because s was initialized with a string literal ... but wide strings in Delphi are not considered links, like regular strings, so it actually has a bit of dynamically allocated heap memory, and as soon as the function returns this memory, you can reuse: (

In this case, it should be good:

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

Here you return a pointer to a local variable. It immediately becomes invalid.

+2
source

Creating dll files on delphi.wikia.com has the answer I was looking for. And the solution too.

For example, Delphi automatically allocates and frees memory to store your lines, it knows when they are no longer needed, etc. The same applies to, for example, Visual Basic, but both do it differently. So, if you need to pass the line that Visual Basic has allocated to a DLL written in Delphi, you would run into big problems, because now both will try to control the line and will go into each other.

The solution is to use FastMM and it works brilliantly !! Now I have a replacement for BORLNDMM.DLL with my project, and everything just works.

+1
source

I just completely straightened up on this, thanks to Rob Kennedy on the news: comp.lang.pascal.delphi.misc

He said, among other things, that:

  • This DLL is not needed by ShareMem, SysUtils or Classes.
  • You took WideString and told the compiler that it really is a pointer to WideString. You are lying to the compiler. It does not bother, but the calling function of this function probably does.

Thus, the redesigned code that works fine without ShareMem (and SysUtils and classes added by the DLL wizard, as it happens), looks like this:

 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' 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=ζ―…θ¨œθ¨ 

All of this works great. The VB6 IDE happily starts the DLL, and the MsgBoxs appear with everything as it should.

0
source

I think we can close it. The code below seems sufficient to maintain a focus on news:comp.lang.pascal.delphi.misc happy, and I really need to move from conceptual testing to doing something with it.

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' got fleas'; result := SysAllocString(PWideChar(s)); end; end. 

Now VB is happy and I don't get weird IDE crashes.

0
source

Source: https://habr.com/ru/post/1277666/


All Articles