首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >遇到一个大问题:Delphi2010中的TDictionary和dll!

遇到一个大问题:Delphi2010中的TDictionary和dll!
EN

Stack Overflow用户
提问于 2010-07-17 08:11:46
回答 3查看 1.1K关注 0票数 1

当我试图从动态加载的动态链接库访问主机程序中的TDictionary变量时,我遇到了一个非常严重的问题。这里是完整的代码,谁能给点帮助?谢谢!

===========main计划项目源code===================

代码语言:javascript
复制
program main;

uses
  ShareMem,
  Forms,
  uMain in 'uMain.pas' {Form1},
  uCommon in 'uCommon.pas';

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

==============unit uMain================

代码语言:javascript
复制
unit uMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, uCommon;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;


var
  Form1: TForm1;


implementation

{$R *.dfm}


type
  Tfoo = function(ADic: TMyDic): string; stdcall;

procedure TForm1.Button1Click(Sender: TObject);
var
  Dic: TMyDic;
  HLib: THandle;
  foo: Tfoo;
begin
  Dic := TMyDic.Create;
  try
    Dic.Add(1, 'World!');
    Dic.Add(2, 'Hello, ');

    HLib := LoadLibrary('Mydll.dll');
    try
      @foo := GetProcAddress(HLib, 'foo');
      ShowMessage(foo(Dic));
    finally
      FreeLibrary(HLib);
    end;
  finally
    Dic.Free;
  end;
end;

end.

=================dll项目源code=====================

代码语言:javascript
复制
library MyDll;

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

function foo(ADic: TMyDic):string; stdcall;
var
  I: Integer;
  S: string;
begin
  for I in ADic.Keys do
  begin
    S := S + ADic[I];
  end;
  Result := s;
end;


exports
  foo;

end.

================unit uCommon==============

代码语言:javascript
复制
unit uCommon;

interface
uses
  SysUtils, Generics.Collections;

type
  TMyDic = TDictionary<Integer, string>;



implementation

end.
EN

回答 3

Stack Overflow用户

发布于 2010-07-17 08:16:31

你有没有遇到异常?可能是访问冲突或无效的指针操作?

如果DLL有自己的内存管理器,则不能在Delphi和DLL之间共享字符串和对象。由于您使用的是Delphi2010,因此默认情况下应该安装FastMM。在使用列表中添加"SimpleShareMem“作为DLL和EXE的第一项,看看这是否不能解决问题?

编辑:针对发贴者提供的其他信息:

在卸载动态链接库之后调用dic.free。即使您共享内存管理器,这也会给您带来访问冲突。这就是为什么。

Free调用TObject.Destroy,这是一个虚拟方法。编译器生成代码以在对象的Virtual Method Table中查找它。但VMT存储在特定于模块的静态内存中,而不是由内存管理器分配的共享内存中。您卸载了DLL,并从对象中的VMT指针下面拔出了地毯,因此当它试图调用虚拟方法时,您会遇到访问冲突。

您可以通过确保在卸载DLL之前调用Free来修复此问题。或者,您可以使用运行时包而不是DLL,后者通过将对象的VMT放在一个外部包中来解决此问题,该外部包在您完成之前不会被卸载。

票数 5
EN

Stack Overflow用户

发布于 2010-07-17 09:47:32

我强烈建议不要在可执行文件和常规DLL之间传递对象实例。主要是因为你遇到的确切原因。如果重新构建了DLL,并且您以某种不兼容的细微方式更改了对象,会发生什么?

正如Mason所指出的,包是将应用程序划分为模块的首选方法。

票数 5
EN

Stack Overflow用户

发布于 2010-07-18 21:04:31

我终于找到了真正的问题所在!看起来是这样的:"For..in keys“循环将导致TDictionary为其数据字段FKeyCollection创建一个实例:

代码语言:javascript
复制
function TDictionary<TKey,TValue>.GetKeys: TKeyCollection;
begin
  if FKeyCollection = nil then
    FKeyCollection := TKeyCollection.Create(Self);
  Result := FKeyCollection;
end;

因此,当动态链接库被卸载时,FKeyCollection所指向的内存也会被释放,从而留下一个“悬空指针”。

代码语言:javascript
复制
destructor TDictionary<TKey,TValue>.Destroy;
begin
  Clear;
  FKeyCollection.Free;  //here will throw an exception
  FValueCollection.Free;
  inherited;
end;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3269613

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档