IsBadCodePtr 
IsBadHugeReadPtr 
IsBadHugeWritePtr 
IsBadReadPtr 
IsBadStringPtr 
IsBadWritePtr 
//下面的例子为什么测试错误?
procedure   TForm1.Button1Click(Sender:   TObject);    
var
    TB:   TForm;
begin
    TB   :=   TForm.Create(nil);
   // Form2.Show;
    TB.Free;
    if   not   IsBadCodePtr(TB)   and   (PPointer(TB)^   =   Pointer(TForm))   then
    begin
      //应该是内存不存在了啊,怎么还会执行到这里?
        TB.Free;
    end;
end;
谢谢各位大哥,希望能帮我下这几个API究竟是怎么样的,我要判断一个对象或者内存有没有创建请问怎么来判断呢?

解决方案 »

  1.   

    我都是这样做的:Create前赋值nil
    Free后赋值nil使用前
    if tb=nil then
        tb := TFrom.Create(nil);
      

  2.   

    谢谢erhan 大哥。我的是网络程序,所有东西都是动态多连接多创建的。不能按照您所说的赋值为nil来判断的!
      

  3.   

    IsBadCodePtr函数已经废止。它并不能保证指针是有效的,或指向的内存能够安全使用。
    而TB内容含有指向TForm类所在地址,所以后者也成立
      

  4.   

    procedure TForm1.Button1Click(Sender: TObject);
    var
      TB: TForm;
    begin
      TB := TForm.Create(nil);
      // Form2.Show;
      FreeAndNil(TB);
      if Assigned(TB) then
      begin
        TB.Free;
      end;
    end;
      

  5.   

    谢谢楼上各位热心的大哥
    我的因为是网络程序,多个socket管理一个客户,偶尔网络不稳定的时候系统探测scoekt断开的时间不一致,所以我的不能想楼上各位人那么说,复制为nil来判断,因为第一个socket创建的对象(连接断开的时候会释放),第二个socket会用到,第二个socket收到网络信息(对象地址)需要判断下内存是否可用。
    楼上谢谢您的freeandnil其实就是free然后:=nil;、这个我的程序类型不能这么用的
    我不想用异常捕获的方法来试探一个地址内存对象是否正常因为我的程序都不用一句异常捕获的。能有判断的方法当然最好。
    所以我需知道有什么方法可判断一个内存指针指向的地址是否可用
      

  6.   

    不知道Assigned可否达到你的要求if not Assigned(pMemberClass) then
      begin
        pMemberClass := TOtherClassType.Create;
        pMemberClass.Assign(aMemberClass);
        //pMemberClass := aMemberClass;
      end;
      

  7.   

    "因为第一个socket创建的对象(连接断开的时候会释放),第二个socket会用到"
    ——
    既然其它socket要用,为什么要在断开连接时释放?该对象为何不能设计为全局的或单例模式?
      

  8.   

    对象的释放与否通过指针是否为nil来判断是最好的,Delphi程序有自己的内存管理机制,
    Form1.Free
    执行之后,该内存区域很可能压根就没被交给Windows,而是留下来,供后面的程序继续使用,这个时候就不好判断该内存区域了,内存区域还能访问,以上函数都没得效果的。想其他办法
      

  9.   

    谢谢大哥您,其他socket可能会用到,并不是一定会用到或所有socket都会用到,看用户的操作,比如发送图片就启动新连接(图片传输socket),《S用主socket传输地址到C,C创建新socket在通过此连接参数回S》,Server的新连接会得到某个动态创建窗口的内存地址的,由于网络可能会出现不稳定原因,可能会导致系统探测到socket断开的时间也不一样。所以才需要知道也谢谢大哥您的答复,您说还能使用,但是那内存区域调用会出现异常错误的,如果以上API没用为什么微软不说明没用
      

  10.   

    根据你的描述,这种动态创建的完全可以记录起来,比如你可以override 构造函数,在里面将自己“注册”到一个list当中。只要有“东西”,就可以在这里找到,具体怎么找,就根据你所能得到的信息了。
    释放时,也要维护这个list。最好将此list管理类,设计为单例。
      

  11.   

    很谢谢大哥的热情,本来也是用数组的,因为考虑到多个上w个客户连接的时候,for循环的话就会导致效率问题。因此就改为发送指针地址然后回传了难道就没有了判断内存有效没的函数吗?
      

  12.   

    Assigned(对象) = false 
      

  13.   

    请看我的原话:
    执行之后,该内存区域很可能压根就没被交给Windows,而是留下来,给你看个例子procedure TForm1.Button3Click(Sender: TObject);
    var
      OBJ : TComponent;
    begin
      Obj := TComponent.Create(NIL);
      Obj.Tag := 1;
      Obj.Free;
      Caption := IntToStr(Obj.Tag);
    end;程序会出错吗?多数时候不会出错,
    而且执行之后Caption='1'
    Delphi程序有自己的内存管理机制,他接管了这部分,供其他地方使用,
      

  14.   

    您好,不是完全流下来了,你的tag可能只在obj偏移不远低地方。要是你对象里面的类型多,也就是创建后内存大的时候,你比如顶一个DWORD类型,在最尾部。那么你那样访问就会异常。真的很谢谢大哥您。
      

  15.   

    TB的Destroy事件加上TB:=nil;再用Assigned判断
    if Assigned(TB) then
    ...
      

  16.   

    我那个例子只是告诉你,Free后的内存具有不确定性,因此用Windows的API是很难作出准确的判断的.
      

  17.   

    TB.Free 执行这句后,虽然TB被释放了,但是TB是指针,指针还存在。你在TB.free前加上TB := nil;后面的函数就运行正确了
      

  18.   

    楼主还在不呢?可以用内HOOK方式解决的哦
      

  19.   

    在哦,谢谢您啊。HOOK方式?大体上是怎么实现呢?
      

  20.   


    unit HookClassDestroyByCheck;interfaceUses
      Windows;//返回True时,Obj已经执行Free或者Obj地址无效, 返回False未执行Free
    Function CheckObjectIsFreeed(Obj : TObject) : Boolean; assembler;implementation{$IFDEF VER150}        // Delphi 7.0   已经验证通过
    {$ELSE}
      {$IFDEF VER210}      // Delphi 2010  已经验证通过
      {$ELSE}
        {$MESSAGE '本单元提供的功能与Delphi版本密切相关,当前Delphi版本未验证.请验证后再使用.'}
      {$ENDIF}
    {$ENDIF}//返回True时,Obj已经执行Free或者Obj地址无效, 返回False未执行Free
    Function CheckObjectIsFreeed(Obj : TObject) : Boolean; assembler;
    asm
      PUSH 1
      PUSH EAX
      PUSH 4
      PUSH EAX
      CALL IsBadReadPtr
      TEST EAX , EAX
      JNZ  @@Exit
        MOV  EAX , [ESP]
        PUSH 4
        PUSH DWORD PTR [EAX]                    //ClassPointer ->> [ESP]
        ADD  DWORD PTR [ESP] , vmtSelfPtr;
        CALL IsBadReadPtr;
        TEST EAX , EAX;
        JNZ  @@Exit
        MOV  EAX , [ESP]
        MOV  EAX , [EAX]
        CMP  EAX , [EAX+vmtSelfPtr]
        JNZ  @@Exit
        MOV  [ESP+4] , 0
      @@Exit:
      POP  EAX
      POP  EAX;
    end;//验证版本,就是看一下System._ClassDestroy的代码是否和这个函数一样
    procedure _OldClassDestroy(Instance: TObject);
    begin
      Instance.FreeInstance;
    end;procedure NewClassDestroy(Instance: TObject);assembler;
    asm
      PUSH EAX;
      PUSH 4;
      PUSH EAX;
      CALL _OldClassDestroy;
      CALL IsBadWritePtr;
      TEST EAX , EAX;
      JNZ  @@Exit
        MOV  EAX , [ESP]
        PUSH 4
        PUSH DWORD PTR [EAX]                    //ClassPointer ->> [ESP]
        ADD  DWORD PTR [ESP] , vmtSelfPtr;
        CALL IsBadReadPtr;
        TEST EAX , EAX;
        JNZ  @@Exit
        MOV  EAX , [ESP]
        MOV  EAX , [EAX]
        CMP  EAX , [EAX+vmtSelfPtr]
        JNZ  @@Exit
        MOV  EAX , [ESP]
        MOV  DWORD PTR [EAX] , 0;
      @@Exit:
      ADD ESP , 4;
    end;procedure UnitInit;
    var
      Buf : Array [0..5] of Byte;
      P : Pointer;
    begin
      Buf[0] := $68;                                //PUSH
      PDWORD(@Buf[1])^ := DWORD(@NewClassDestroy);  //Adr
      Buf[5] := $C3;                                //Ret
      asm
        LEA  EAX , System.@ClassDestroy;
        MOV  P , EAX;
      end;
      WriteProcessMemory(Windows.GetCurrentProcess() , P , @Buf , 5 , PDWORD(NIL)^);
    end;initialization
      UnitInit;
    end.
      

  21.   

    to kiboisme
      如果按楼主前面的做法,对象变量是在方法里声明,也就是局部变量。那么此方法是否还有效呢?这个地方值得怀疑。
      

  22.   

    代码已经考虑了局部变量的情况,而且这是完整研究了System.pas以及GETMEM.INC给出的代码,只要不是刻意构造,该函数不会出问题.刻意构造地址,可能让函数判断出错.