procedure TForm1.Button1Click(Sender: TObject);
begin
Form2 := TForm2.Create(nil);
end;procedure TForm1.Button2Click(Sender: TObject);
begin
Form2.Show;
end;procedure TForm1.Button3Click(Sender: TObject);
begin
Form2.Free;
end;procedure TForm1.Button4Click(Sender: TObject);
begin
if Assigned(Form2) then ShowMessage('OK') else ShowMessage('NOT');
end;
如何在按BUTTON2之前知道FORM2已经创建并且是一个有效的对象?(注意:如何判断是一个有效的对象?)
begin
有效
end;
Form2.show
简单的说有效对象是指可以正常使用的。首先Form2没有被Create的时候,Assigned(Form2)是False,当然Form2肯定是无效的。这个没有问题,然后我们Form2 := TForm2.Create 创建了一个实例,此时我们Assigned(Form2)是True,答案也是肯定的。此时我们可以执行Form2.Free将Form2释放后,这个时候再用Assigned(Form2)来判断是否是有效的对象就不行了。这个就是我说的是否有效了。
implementation
uses Unit2;
{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
begin
Form2 := TForm2.Create(Application);{注意这里加了Owner为Application}
end;procedure TForm1.Button2Click(Sender: TObject);
begin
Form2.Show;
end;procedure TForm1.Button3Click(Sender: TObject);
begin
Form2.Free;
end;procedure TForm1.Button4Click(Sender: TObject);
begin
if Assigned(Form2) and (Application.FindComponent('Form2') <> nil) then
ShowMessage('OK') else ShowMessage('NOT');
end;
再就是尽量使用FreeAndNil()释放对象,就可以避免用Assigned()检查失败了
而平时我们仅用Free来释放对象,这样仅释放堆上的对象实体,而对栈上的对象引用没做任何操作!
所以在释放对象时,需要FreeAndNil
我有一个项目是MDI模式的,MainForm为EXE,ChildForm为DLL方式的。ChildForm创建后可以传递给MainForm,但是ChildForm一旦caFree后,MainForm就无法跟踪他了。我目前做法是关闭时通过给mainForm发送一条消息来跟踪。所以才会提问,看有没有什么好的方法来得知对象是否有效。也就是说有2个指向一个实例(通过指针赋值的)。一个指针在exe里(Ptr1),一个指针在dll里(Ptr2),通过dll里窗体执行caFree来释放并关闭ChildForm(Ptr2),可以设置FreeAndNil(Ptr2)随便你怎么处理,但是exe里(Ptr1)的指针还是有所指向的。这样就导致exe和dll之间的管理、控制关系的脱节。
我有一个项目是MDI模式的,MainForm为EXE,ChildForm为DLL方式的。ChildForm创建后可以传递给MainForm,但是ChildForm一旦caFree后,MainForm就无法跟踪他了。我目前做法是关闭时通过给mainForm发送一条消息来跟踪。所以才会提问,看有没有什么好的方法来得知对象是否有效。 也就是说有2个指向一个实例(通过指针赋值的)。一个指针在exe里(Ptr1),一个指针在dll里(Ptr2),通过dll里窗体执行caFree来释放并关闭ChildForm(Ptr2),可以设置FreeAndNil(Ptr2)随便你怎么处理,但是exe里(Ptr1)的指针还是有所指向的。这样就导致exe和dll之间的管理、控制关系的脱节。
var classPtr, tmpptr: Pointer;
begin
Result := False;
if objptr = nil then Exit; classPtr := PPointer(objptr)^;
while (classPtr <> nil) and (classPtr <> TObject) do
begin
tmpptr := Pointer(Integer(classPtr) + vmtParent);
if IsBadReadPtr(tmpptr, Sizeof(Pointer)) or
IsBadReadPtr(PPointer(tmpptr)^, Sizeof(Pointer)) then
break;
classPtr := PPointer(PPointer(tmpptr)^)^;
end;
Result := classPtr = TObject;
end;
如果窗体对象是在DLL中的导出函数创建的,那么就由DLL中导出一个释放窗体的函数,那么需要释放的时候,就由EXE调用这个导出函数来释放窗体对象,顺便把EXE中的窗体对象指针置为nil。
如果窗体对象是由DLL中的导出类在EXE中创建的,那么就直接在EXE中释放掉,顺便把EXE中的窗体对象指针置为nil。
有想过应该可以通过VMT来解决这个我问题,但是思想还没有成熟。多谢coffeemay的代码。上面的对话已经说明了不能简单的用Assigned来判断对象是否有效。上面我也给出了我的维护方法了,我在考虑有没有更好的方法来解决。原则是原则,具体的程序千变万化的。如果由DLL中导出释放函数,那必然是由EXE来调用的。我现在的问题是DLL自己把自己关闭了,EXE是处于被动的。所以无法跟踪DLL的真正状态了。