Тестирование Delphi DLL вылетает VB6 IDE - PullRequest
4 голосов
/ 11 октября 2008

Я впервые попробовал написать DLL в Delphi. Все идет нормально. Используя typelib, я без труда смог передать Widestrings в и из 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 ]

2 голосов
/ 11 октября 2008
result := PWideString(s);

Вы возвращаете указатель на локальную переменную здесь. Он немедленно становится недействительным.

1 голос
/ 11 октября 2008

Создание DLL на сайте delphi.wikia.com есть ответ, который я искал. И решение тоже.

Например, Delphi автоматически выделяет и освобождает память для хранения ваших строк, она знает, когда они больше не нужны и т. Д. То же самое относится, например, к. Visual Basic, но оба делают это по-разному. Таким образом, если вы передадите строку, выделенную Visual Basic, в DLL, написанную на Delphi, у вас возникнут большие проблемы, потому что теперь оба будут пытаться управлять строкой и попадать друг другу в голову. 1007 * Решение состоит в том, чтобы использовать FastMM , и это прекрасно работает !! Теперь у меня есть замена BORLNDMM.DLL в моем проекте, и все просто работает.

1 голос
/ 11 октября 2008

Чтобы уточнить ответ GSerg:

result := PWideString(s);

вы бы подумали, что все будет в порядке, потому что s инициализируется строковым литералом ... но широкие строки в Delphi не считаются ссылками, как обычные строки, поэтому s фактически содержит немного динамически выделяемой динамической памяти, и, как только когда функция возвращает эту память, ее можно использовать повторно: (

Хотя все должно быть в порядке:

function foo() : PWideString;
const s : WideString = 'My dog''s got fleas';
begin
  result := PWideString(s);
end;
0 голосов
/ 17 октября 2008

Я думаю, что мы можем закрыть это. Приведенного ниже кода, кажется, достаточно, чтобы люди остались довольны 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.

Теперь В.Б. доволен, и у меня не получаются странные сбои в IDE.

0 голосов
/ 15 октября 2008

Я только что полностью поправился, благодаря Робу Кеннеди в новостях: comp.lang.pascal.delphi.misc

Он сказал, среди прочего, что:

  1. Эта DLL не нуждается в ShareMem, SysUtils или Classes.
  2. Вы взяли WideString и сказали компилятору, что это действительно указатель на WideString. Ты врешь компилятору. Это не волнует, но вызывающая сторона этой функции, вероятно, делает.

Таким образом, пересмотренный код, который отлично работает без ShareMem (и SysUtils и Classes, которые были добавлены мастером DLL, как это происходит) выглядит следующим образом:

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

Все это прекрасно работает. IDE VB6 успешно запускает DLL, и MsgBoxs появляются со всем, как и должно быть.

...