我在dll中为Treeview添加Node,但是在dll中添加的Node一clear就出错,大家帮帮忙看一下,很急!(100分)

  • 主题发起人 主题发起人 dirk
  • 开始时间 开始时间
简化的代码:
library Project1;

uses
SysUtils,
Controls,
Dialogs,
windows,
Classes,
ComCtrls;

{$R *.RES}

procedure GetTV_Node(TV:TTreeView);stdcall;
begin
TV.Items.Clear
TV.Items.Add(nil,'Root');
TV.Items.Add(nil,'Node1');
TV.Items.Add(nil,'Node2');
TV.Items.Add(nil,'Node3');
end;

exports
GetTV_Node;

begin
end.

==================================================================

unit Unit1;

interface

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

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

var
Form1: TForm1;

implementation

{$R *.DFM}
procedure GetTV_Node(TV:TTreeView);stdcall;External'project1.dll';

procedure TForm1.Button1Click(Sender: TObject);
begin
GetTV_Node(TreeView1);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
TreeView1.Items.Clear
end;

end.

我想错误不在clear,而是add过程中,VCL有什么地方没处理好。
 
正在发送中,你试试看,共270K,d5下通过。
两个button都能按数次没问题。
 
是的,没错,我知道错误的原因了,是string生存期的问题,我前不久在另一个人的帖子里
看到过类似的问题。

非常感谢testnet,我昨晚呼叫了很多在线高手,除了“卷卷”回复说网速慢,打不开帖子
外,谁也不理我,真的很感谢你,愿意帮助我!
 
在你的DLL工程文件中和你的应用程序的工程文件中的uses语句后加上ShareMem这个单元
可避免这个错误,这是由于Delphi的String动态管理内存机制造成的!
注意是在工程文件中的uses中加,而不是在unit单元中加,牢记!!!而且是DLL和应用程序都要加
如果应用程序不加则在退出时报错!!!

delphi6 下调试通过!
 
抱歉!昨晚我没有看到你的寻呼!今天早上也是忙了好长时间,你在写上面的句子的时候我
正在找解决的办法,后来贴上去才发现你已经解决了!
 
谢谢only you,但是,你说的我试了一下,这样程序即使什么也不做,运行、关闭,
就会出那个错。
 
关注。终于搞完了。我学习。虽然Build with package可以,但这个不失为好方法。

学习啊。我看看其他的解答方法有没有?

 
我的代码如下
library Project1;

{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }

uses
ShareMem,
SysUtils,
Classes,
ComCtrls;

{$R *.res}

procedure GetTV_Node(TV:TTreeView);safecall;
begin
TV.Items.Clear
TV.Items.Add(nil,'Root');
TV.Items.Add(nil,'Node1');
TV.Items.Add(nil,'Node2');
end;

exports
GetTV_Node;
begin
//CoInitialize(nil);
end.



工程文件中:
program Pmy;

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

{$R *.res}

begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
 
Nizvoo,你能说一下“Build with package”方法的使用吗?不是很明白你的意思,我想
在这里以我的理解总结一下这个问题所在:

一、问题是出在TV.Items.Add(nil,'root1')中,可能是在GetTV_Node过程结束后,在过程
中为'root1'分配的内存空间即被释放,所以在clear时,要释放相应的资源时,就出错,
因为要释放一个已经释放的空间;

二、testnet的方法之所以正确(TV.Items.Add(nil,strRoot)),是因为他用的strRoot变
量是dll中的全局变量,它的生存期是整个exe的生存期,所以,它的内存空间始终是存在内
存中的;

三、始终搞不懂的是,为什么在exe的过程中用TV.Items.Add(nil,'root1'),在过程结束后
'root1'的内存空间也应该是释放的,但用clear却不出错,而在dll中一样的方法,却出错,
dll分配的内存空间难道不是在exe中的吗?用only you的方法,uses了sharemem,但更错了。
而且,用testnet的方法,有个问题,如果在程序这改变了dll中全局变量的内容,会造成怎样
的后果?我做了个小测试,结果,出现了无法解释的错误,我还想把这些问题也搞搞清楚啊!

请大家接着发言吧,等彻底解决了,我再开个帖子给大家加分。
 
不会吧!我试了,如果不加ShareMem,我贴的上面的代码就有问题,如果加了则一点问题都没有,
干脆我贴全部的代码,你仔细测试一下!
/***
我再次说明,ShareMem必须放在工程文件中而不是unit文件中,而且必须是第一个,
其它任何位置都不行!!!!!!!!!!!!!!!!!!!!
***/

动态连接库
library Project1;

{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }

uses
ShareMem,
SysUtils,
Classes,
ComCtrls;

{$R *.res}

procedure GetTV_Node(TV:TTreeView);safecall;
begin
TV.Items.Clear

TV.Items.Add(nil,'Root');
TV.Items.Add(nil,'Node1');
TV.Items.Add(nil,'Node2');
end;

exports
GetTV_Node;
begin
//CoInitialize(nil);
end.


测试工程文件
program Pmy;

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

{$R *.res}

begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

用到的unit
unit mianUnit;

interface

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

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

var
Form1: TForm1;

implementation

{$R *.dfm}
var
HLib:THandle;
Proc:procedure (TV:TTreeView);safecall;
procedure TForm1.Button1Click(Sender: TObject);
begin
HLib:=LoadLibrary('Project1.dll');
Proc:=GetProcAddress(HLib,'GetTV_Node');
Proc(TreeView1);
FreeLibrary(HLib);
end;

end.



 
//dll Project:

library Project2;

{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }

uses
ShareMem,
SysUtils,
Classes,
ComCtrls;

{$R *.RES}
procedure GetTV_Node(TV:TTreeView);safecall;
begin
TV.Items.Clear
TV.Items.Add(nil,'Root');
TV.Items.Add(nil,'Node1');
TV.Items.Add(nil,'Node2');
end;

begin
end.

//测试工程文件:

program Project1;

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

{$R *.RES}

begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

unit Unit1;

interface

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

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

var
Form1: TForm1;

implementation

{$R *.DFM}
procedure GetTV_Node(TV:TTreeView);stdcall;External'project2.dll';

procedure TForm1.Button1Click(Sender: TObject);
begin
GetTV_Node(treeview1);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
treeview1.Items.Clear
end;

end.

一运行就出错,D5。
 
将你的静态引用改为动态引用试试!
如下
var
HLib:THandle;
Proc:procedure (TV:TTreeView);safecall;
procedure TForm1.Button1Click(Sender: TObject);
begin
HLib:=LoadLibrary('Project1.dll');
Proc:=GetProcAddress(HLib,'GetTV_Node');
Proc(TreeView1);
FreeLibrary(HLib);
end;
 
而且我用你的代码在Delphi 6 +win xp下测试通过,没有任何问题,
>>一运行就出错!
会不会是你的动态连接库没找到,你将最新编译好的代码(dll)放在
你测试工程同样的文件夹下试试!!
 
不行,我的dll名称是'Project2.dll',所以,我只改了这个部分,但是却出现这样的错误:
"Access violation as address 00000000.Read of address 00000000"
是在Proc(TreeView1);时错的。
 
only you,我用你贴出来的代码,新建了一个项目(包含exe、dll),运行会出错,
但是把sharemem加到我昨晚写的例子中,倒也不出错了,这是怎么回事?

我是win2000+d5
 
那就怪了!无论是你的还是我的,我测试都没问题呀!我跟踪了一下代码!却信是因为缺shareMem
导致的错误!要不你先按我的代码做一个全新的测试,如果还有问题那我也没办法了!
理论上无论delphi 5 还是 6都应该没有问题!
 
你一定是那里写错了!,或者DLL连接库名写错了,或者是在调用的时候写错了!
总之是shareMem搞的鬼!加上它肯定OK的!
 
对不起,给你的例子我少写了引出部分,呵呵!!!正确的写法如下
library Project1;

{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }

uses
ShareMem,
SysUtils,
Classes,
ComCtrls;

{$R *.res}

procedure GetTV_Node(TV:TTreeView);safecall;
begin
TV.Items.Clear
TV.Items.Add(nil,'Root');
TV.Items.Add(nil,'Node1');
TV.Items.Add(nil,'Node2');
end;

exports
GetTV_Node;<<<---------------这里
begin
//CoInitialize(nil);
end.
 
是的,你说的是对的,确实是因为缺shareMem导致的错误,而可笑的是正是按你的代码做
的全新的dll+exe才出的错,在原来的project中,注释掉了所有testnet的代码后,按你的
说法,在dpr的第一个uses处加上sharemem,运行果然不错,于是,我有新建了dll和exe
项目,照你的代码写入,编译,运行,结果……… :( ,太奇怪了!
 
呵呵呵,我晕倒!害得我莫名其妙了老半天,哈哈哈,解决了!
 

Similar threads

后退
顶部