Search code examples
delphidllvb6typelib

Testing Delphi DLL crashes VB6 IDE


I've had my first go at writing a DLL in Delphi. So far so good. By using a typelib I've been able to pass Widestrings to and from the DLL without difficulty.

What's curious at the moment is that I'm using VB6 as the testbed, and every time I run a test within the IDE, the program runs and then the IDE process suddenly disappears from memory - no error messages, nothing. If I step through the code, everything works fine until I execute the last line, then the IDE disappears.

By contrast, when I compile the test to an EXE the program runs to its end, without error messages etc.

Has anyone had this problem before and is there an obvious solution that's staring me in the face?

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

I moved the declaration of the WideString outside of the function in which I had declared it, in the expectation that that would increase the lifetime of the variable to longer than just the lifetime of the foo function. It made no difference whatsoever.

Likewise I commented out of the VB6 the call to the foo function. That made no difference either. No matter what I do, VB6 IDE dies after the last line of code is executed.

Something apart from pointers to local variables is the cause. But what?


Solution

  • To elaborate on GSerg's answer:

    result := PWideString(s);
    

    you'd think it would be ok because s was initialized with a string literal... but wide strings in Delphi are not reference counted like normal strings, so s actually holds a bit of dynamically allocated heap memory, and as soon as the function returns this memory can be reused :(

    The following should be ok though:

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