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

  • 主题发起人 主题发起人 dirk
  • 开始时间 开始时间
D

dirk

Unregistered / Unconfirmed
GUEST, unregistred user!
一个dll,其中一个函数接受一个TTreeView对象参数,然后为这个TTreeView添加若干
Node,然后在主程序中放置一个TTreeView:TreeView1,做为传给dll的参数,传递前
已经创建好了,也在主程序关闭时自动释放,但是,在TreeView1在clear时,就会出
下面这个错误:
Project Project1.exe raised exception class EInvalidPointer with message 'Invalid pointer operation'.Process stopped.Use Step or Run to continue.
如果不clear,那么这个错误在程序退出时也会出现。
我试过了,只要是在dll中添加的Node,不管是在dll中clear,还是在主程序中clear,
都会出这个错,而在主程序中添加Node,在主程序中clear,就不会出错,为什么?

请大家帮个忙,我急!

///////以下是dll Project:

library Project3;

uses
SysUtils,
Controls,
Dialogs,
windows,
Classes,
ComCtrls,
Db, ADODB,
ActiveX;

type

{$R *.RES}

//var
// TT:TTreeView;

procedure GetTV_Node(var TV:TTreeView);stdcall;
begin
TV.Items.Clear
// <--出错啊!!!!!

TV.Items.Add(nil,'Root');
TV.Items.Add(nil,'Node1');
TV.Items.Add(nil,'Node2');
// TT:=TV;
end;

exports
GetTV_Node,

begin
CoInitialize(nil);
// ADOC:=TADOConnection.Create(nil);
// ADOQ1:=TADOQuery.Create(nil);
// ADOC.LoginPrompt :=false;
// ADOC.ConnectionString :='DRIVER={SQL Server};server=10.10.10.10;database=mydb;uid=sa;pwd=';
// ADOC.Open
// ADOQ1.Connection :=ADOC;
// ADOQ1.SQL.Add('select * from tbuser');
// ADOQ1.Open
end.


///////以下是主程序 Project:
unit Unit1;

interface

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

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

var
Form1: TForm1;

implementation

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

procedure TForm1.Button5Click(Sender: TObject);
begin
GetTV_Node(TreeView1);
end;
end.
 
TT:=TV;这个似乎有问题

一个方案,
 在DLL中增加一个线程类,用线程类的 Synchronize()方法来执行GetTV_Node中的代码
 
不是吧,这行我已经注释掉了,而且,我觉得应该没有问题,因为TT只是一个指针。

我的问题是为什么在dll中添加的Node在clear时会出错,
roject Project1.exe raised exception class EInvalidPointer with message 'Invalid pointer operation'.Process stopped.Use Step or Run to continue.
而且在程序关闭时也会出这个错,但奇怪的是,我跟踪dll,发现虽然clear出错,但在其
后面的语句却仍然执行,所以,虽然程序出错,但执行的结果却是正确的,为什么?

大家帮我看看吧!先谢了,要分还可再加!
 
Build with Package

你那个问题我忘了~~~
就试
 
Build with Package?
看不懂!
 
这个是权且之计
可能要传入相应参数
如TApplication,TScreen

Project -> Options

里头Package里头的勾打上。

你昨天ADO数据调用我试了,可以的。

我用的是D6.0啊

 
>可能要传入相应参数
>如TApplication,TScreen
怎么做?有没有例子?

昨天那个问题的焦点不是ADO数据可否调用,而是
一、CoInitialize,CoInitializeEx,OleInitialize的区别;
二、dll的卸载部分怎么写?
关于二,你说
initialization
Coinitialize(nil);
finalization
CoUninitialize;
这样写,但是错的,initialization、finalization根本不能出现在.dpr文件中!
而你说的放在Unit中,根本和我的问题不是一回事。
 
建议用句柄和API进行操作不用在DLL传Delphi类!

详细见commctrl的TreeView_xxxxxx的API,你的原因我不清楚!
 
to tan_jian:
你是指看TreeView的源码,用api操作吗?
 
对就是这个意思!不是看源代码!就是TreeView_InsertItem相关的API(commctrl.pas)

具体用法和VC中的差不多!
 
procedure TForm1.Button1Click(Sender: TObject);
var Node: TV_INSERTSTRUCT;
i,j: integer;
item: tagTVITEMA;
H: HTREEITEM;
s: string;
begin
TreeView_DeleteAllItems(Tree);
node.hInsertAfter:=nil;
item.mask:=1;
item.state:=1;
item.stateMask:=0;
item.cchTextMax:=10;
Item.iImage:=0;
Item.iSelectedImage:=0;
Item.cChildren:=1;
Item.lParam:=0;
for i:=1 to 5 do
begin
Node.hParent:=nil;
node.hInsertAfter:=node.hInsertAfter;
item.pszText:=Pchar(IntToStr(i));
node.item:=item;
H:=TreeView_InsertItem(Tree,Node);
node.hParent:=H;
s:='';
for j:=1 to 5 do
begin
s:=s+InttoStr(i);
node.item.pszText:=Pchar(s);
TreeView_InsertItem(Tree,Node);
end;
end;
end
//才写的一段代码,第一次对树形组件全用API,你运行一下对照程序就明白了!

Tree:=Treeview1.Handle
//var Tree: THandle;

由于时间仓卒,对于结构体一些东西可能未明白!有什么错误,请指正!
 
谢谢,我试试先。
 
的确不出那个错了,但是,这么做实在比较累,要是用能直接用VCL组件多方便,
我看了一下TTreeNodes的源码,其实就是用了CommCtrl单元的TV_INSERTSTRUCT、
TreeView_InsertItem和TreeView_DeleteAllItems等,但是,TTreeView的items的
clear、add等其实就是用了这些函数,怎么通过TTreeView调用就会出错,直接用这
些函数做就不会错?

谁要是能解释一下就好了!
 
我看能不能做这样的猜测:

1、EXE有一个监测机制,监测所有创建VCL的动作,包括NODE。
2、调用DLL创建任意VCL,监测机构会失去控制权。
3、返回后监测机制无法得知该新NODE的具体内存分配。
4、EXE终止时,监测机构负责释放没有显式释放内存的组件的内存。
5、对于DLL创建的这部分内存,监测机构不知道怎么样释放。
6、于是按SizeOf(TTreeNode)强制释放,但是事实上可能创建了一个象PString的东西并显式New()。
7、操作系统也没办法,不得不显示:'Invalid pointer operation'。

解决办法我看能不能在OnDelete写段代码,显式释放该Node占用的内存。
OnDelete事件会在Clear命令执行之前发生。
 
我看了TTreeNodes的clear方法的代码:
procedure TTreeNodes.Clear;
begin
ClearCache;
if not (csDestroying in Owner.ComponentState) and Owner.HandleAllocated then
TreeView_DeleteAllItems(Owner.Handle);
end;
也是用了TreeView_DeleteAllItems(Owner.Handle);为什么我用clear就会出
'Invalid pointer operation'这个错,而用TreeView_DeleteAllItems就不出错?
 
发现,其实不是clear方法执行时出错,而应该是添加node中有错,但不知道是什么,难道
是delphi的bug?

tan_jian的方法是可以不再出错,但程序看不懂,也太麻烦,VCL应该能解决这个问题的,
而且,不能改Node的text,请高手们帮我解决这个问题。
 
{ Important: Methods and properties of objects in VCL or CLX can only be used
in a method called using Synchronize,}
原因可以是上面这句,虽然不用Synchronize也可以操作主界面。
我试了一下在DLL中用Synchronize方法,发现它不运行这函数,停了,不知为什么。

另一个方法,在DLL中这样更新 
procedure.UpdataTTreeView;
var
tn:TTreeNode;
begin
FTV.Items.Clear;
tn:=TTreeNode.Create(FTV.Items);
SetLength(s,100); //最重要是这句,我试了一个节点,用clear没问题
          //   s是与DLL同样生存期的变量。
          //  FTV:TTreeView,是传进来的哪个TV
          // D6 updata2 (6.02)下通过
s:='cccccc';
tn.Text:=s;
FTV.Items.Add(tn,s);
end;
 
我是D5,还是一样的错误。
{ Important: Methods and properties of objects in VCL or CLX can only be used
in a method called using Synchronize,}
这句话怎么翻译?
 
把你的代码简化后给我试试,(dll exe),不一定有答案
testnet@etang.com
 

Similar threads

后退
顶部