测试Delphi DLL崩溃VB6 IDE

时间:2008-10-11 04:36:02

标签: delphi dll vb6 typelib

我第一次使用Delphi编写DLL。到现在为止还挺好。通过使用类型库,我已经能够毫无困难地将宽带传递给DLL。

目前令人好奇的是我使用VB6作为测试平台,每次我在IDE中运行测试时,程序运行然后IDE进程突然从内存中消失 - 没有错误消息,没有。如果我单步执行代码,一切正常,直到我执行最后一行,然后IDE消失。

相比之下,当我将测试编译到EXE时,程序运行到最后,没有错误消息等。

之前有没有人遇到这个问题,是否有一个明显的解决方案让我盯着我?

以下源代码,如果重要:

- 项目

library BOSLAD;

uses
  ShareMem,
  SysUtils,
  Classes,
  BOSLADCode in 'BOSLADCode.pas';

exports
  version,
  DMesg,
  foo;
{$R *.res}

begin
end.

- 单位

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

我将WideString的声明移到我声明它的函数之外,期望这会将变量的生命周期增加到比foo函数的生命周期更长的时间。它没有任何区别。

同样,我在VB6中注释了对foo函数的调用。这没有任何区别。无论我做什么,VB6 IDE都会在最后一行代码执行后死掉。

除了指向局部变量的指针之外还有其他原因。但是什么?

5 个答案:

答案 0 :(得分:2)

result := PWideString(s);

您在这里返回指向局部变量的指针。它立即变得无效。

答案 1 :(得分:1)

详细说明GSerg的回答:

result := PWideString(s);

你认为这样可以,因为s是用字符串文字初始化的...但是Delphi中的宽字符串不像普通字符串一样被引用,所以s实际上拥有一些动态分配的堆内存,并且很快当函数返回时,可以重用此内存:(

以下情况应该没问题:

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

答案 2 :(得分:1)

delphi.wikia.com网站上的

Creating DLLs有我一直在寻找的答案。也是解决方案。

例如,Delphi会自动分配和释放内存以存储您的字符串,它知道何时不再需要它们等。同样适用于例如Visual Basic,但都以不同的方式进行。因此,如果你要将一个由Visual Basic分配的字符串传递给用Delphi编写的DLL,那么你最终会遇到大麻烦,因为现在它们都会尝试管理字符串并且会陷入彼此的头发。

解决方案是使用FastMM,它的工作非常出色!!我现在有一个替换BORLNDMM.DLL in我的项目,一切正常。

答案 3 :(得分:0)

我刚刚在这个问题上彻底理顺了,感谢Rob Kennedy的新闻:comp.lang.pascal.delphi.misc

他说,其中包括:

  1. 此DLL不需要ShareMem,SysUtils或Classes。
  2. 您已经使用了WideString并告诉编译器它实际上是指向WideString的指针。你骗了编译器。它并不关心,但这个函数的调用者可能会这样做。
  3. 所以修改后的代码在没有ShareMem(以及DLL向导添加的SysUtils和Classes)的情况下工作正常如下:

    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=毅訜訝
    

    所有这一切都很完美。 VB6的IDE很高兴地运行DLL,并且MsgBoxs出现了应有的一切。

答案 4 :(得分:0)

我想我们可以关闭这个。下面的代码似乎足以让人们对news:comp.lang.pascal.delphi.misc感到高兴,我真的需要从概念测试转向实际使用它。

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.

现在VB很开心,我不会得到奇怪的IDE崩溃。