unit UnitMain;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons;type
  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    procedure BitBtn1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;
 function threadfunc(StartPos: pointer):integer ;stdcall;  //
implementation{$R *.dfm}function threadfunc(StartPos: pointer):integer ;stdcall;  //
var
 s,i:integer;
begin
 i:=0;
 try
 s := s div i;
 except end;
end      ;
procedure TForm1.BitBtn1Click(Sender: TObject);
var
 cThreadId,cThreadId2 :cardinal;
begin
  beginthread(nil,1024,@threadfunc2,nil,0,cThreadId2);
end;end.如上代码,当我单击运行的时候,程序自动全部退出来,只是线程出现异常怎么 整个程序都退了出来,我设置的 try except 不好用请问各位大侠,我如何在线程里捕获这个异常

解决方案 »

  1.   

    更正一下,代码不变,我点击按钮的时候,启动了线程,然后 程序自动全部退出来,只是线程出现异常怎么 整个程序都退了出来,我设置的 try except 不好用 请问各位大侠,我如何在线程里捕获这个异常
      

  2.   

    beginthread函数是怎么定义的?Delphi里的线程编程, 建议直接从TThread类继承, 不要用Windows API中的线程函数。
      

  3.   

    unit UnitMain; interface uses 
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
      Dialogs, StdCtrls, Buttons; type 
      TForm1 = class(TForm) 
        BitBtn1: TBitBtn; 
        procedure BitBtn1Click(Sender: TObject); 
      private 
        { Private declarations } 
      public 
        { Public declarations } 
      end; var 
      Form1: TForm1; 
     function threadfunc(startPos:Pointer):integer ;cdecl;
    implementation {$R *.dfm} function threadfunc(startPos:Pointer):integer ;cdecl;
    var 
    s,i:integer; 
    begin 
    i:=0; 
    try 
    s := s div i; 
    except 
      raise;
    end; 
    end      ; 
    procedure TForm1.BitBtn1Click(Sender: TObject); 
    var 
    cThreadId,cThreadId2 :cardinal; 
    begin 
      beginthread(nil,1024,@threadfunc2,nil,0,cThreadId2); 
    end; end. 
    基本上沒有問題,應該調用的方式問題。
      

  4.   

    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
      function threadfunc(startPos:Pointer):integer ;cdecl;//stdcall;  //
    var
      Form1: TForm1;
      V : Tthread;implementation{$R *.dfm}function threadfunc(startPos:Pointer):integer ;cdecl;
    var
      s,i:integer;
    begin
      i:=0;
      s := 3;
     try
       s := s div i;
       Result := s;   // 還有這裏,不管怎麼樣,如果你一定想測這個異常,就加上這個返回代碼,不然讓編譯器優化掉後,即使代碼是有異常但也不會被執行。
     except
       raise;
     end;
    end      ;procedure TForm1.Button1Click(Sender: TObject);
    var
      cThreadId,cThreadId2 :cardinal;
    begin
     cThreadId := beginthread(nil,0,@threadfunc,Pointer(Self),CREATE_SUSPENDED,cThreadId2);
     ResumeThread(cThreadId)
    end;end.
      

  5.   


    記住上面的  stacall  轉為  cdecl  或者不要帶
      

  6.   

    为什么 stdcall就不行,cdecl 就可以
      

  7.   

     查CSDN就明白了。
      beginthread  cdecl 壓棧,   由調用者管理。
     
      

  8.   

    starluck说的不正确。BeginThread是Delphi的System单元中定义的一个函数, 代码如下:function BeginThread(SecurityAttributes: Pointer; StackSize: LongWord;
      ThreadFunc: TThreadFunc; Parameter: Pointer; CreationFlags: LongWord;
      var ThreadId: LongWord): Integer;
    var
      P: PThreadRec;
    begin
      New(P);
      P.Func := ThreadFunc;
      P.Parameter := Parameter;
      IsMultiThread := TRUE;
      Result := CreateThread(SecurityAttributes, StackSize, @ThreadWrapper, P, CreationFlags, ThreadID);
    end;
    其中调用了Windows API函数CreateThread来创建线程。 CreateThread的定义如下:
    HANDLE CreateThread(
        LPSECURITY_ATTRIBUTES lpThreadAttributes, // pointer to thread security attributes  
        DWORD dwStackSize, // initial thread stack size, in bytes 
        LPTHREAD_START_ROUTINE lpStartAddress, // pointer to thread function 
        LPVOID lpParameter, // argument for new thread 
        DWORD dwCreationFlags, // creation flags 
        LPDWORD lpThreadId  // pointer to returned thread identifier 
       );
     
    第三个参数就是线程代码入口地址, LPTHREAD_START_ROUTINE的定义如下:
    DWORD WINAPI ThreadFunc( LPVOID );显然:
    1. 这个线程函数是一个无参数的函数, (StartPos: pointer)这部分是不能写的,否则会出现异常。
    2. 这个线程函数是使用stdcall的调用约定的。
      

  9.   


    不好意思,的確是看錯了。 應該是想到了   __BeginThread 的影響显然: 
    1. 这个线程函数是一个无参数的函数, (StartPos: pointer)这部分是不能写的,否则会出现异常。   // 怎麼可能跟它有關呢。呵呵 
    2. 这个线程函数是使用stdcall的调用约定的。   我只是想到了 cdecl,stacacll  清棧的問題,沒有注意查,保歉
    threadFun 是一個: 
    DWORD WINAPI ThreadProc(
      LPVOID lpParameter
    );//無類型的定義吧, 即這個參數可以是任何類型。  其實他這個程序最主要的問題就在於:function threadfunc(startPos:Pointer):integer ;cdecl;
    var
      s,i:integer;
    begin
      i:=0;
      s := 3;
     try
       s := s div i;
       Result := s;   // 這句,這句必須有。一個沒有返回值的函數,我想是不會拋出異常的。因為它根本就不執行
     except
       raise;
     end;
    end      ;
      

  10.   

    function threadfunc(startPos:Pointer):integer ;cdecl;
    還有一個原因,我個人的理解; startPos:Pointer   這個參數帶上後,加上 stdcall; 就變向指定了,由函數自己清理堆棖,這個無類型參數就成了罪魁禍首了。
    但如查你采用 cdecl 就不會出錯,因為調用者也沒有清棧。所以不會出錯。
      

  11.   

    可以使用从 TThread类继承 
    这样使用VCL提供的多线程也许会安全些
      

  12.   

    按照DWORD WINAPI ThreadFunc( LPVOID )的约定, 线程函数是不带参数,所以Windows内核在调用ThreadFunc时,没有把任何参数压入栈。ThreadFunc如果申明成这样:function threadfunc(startPos:Pointer):integer;  stdcall;则编译出的代码中, 在ThreadFunc函数返回时会弹出栈里的参数,这是stdcall约定所要求的“参数由调用者入栈,出栈由函数负责”。
    而栈内其实并没有调用时压入的参数,这将会导致栈异常。ThreadFunc如果申明成这样:function threadfunc(startPos:Pointer):integer;  cdecl;编译出的代码中, 在ThreadFunc函数返回时不会对栈进行操作, 这是cdecl约定所要求的“参数入/出栈均由调用者负责”,所以不会出现异常。
    不过, 还是应该按照DWORD WINAPI ThreadFunc( LPVOID )的约定来写线程函数, 不要带参数(带了也没用,参数并未被赋值), 以免混乱。
      

  13.   

    1. 这个线程函数是一个无参数的函数, (StartPos: pointer)这部分是不能写的,否则会出现异常。   // 怎麼可能跟它有關呢。呵呵 我的解释都是建立在stdcall调用约定基础上的,当然和(StartPos: pointer)这部分有关。
      

  14.   

    这个问题, 还是遵守Windows API的约定, 比较好。
      

  15.   

     不過這確是。 通過這個線程,感覺 stdcall,cdecl  還挺有意思的。   秀峰看到這段代碼了嗎? {$IFDEF MSWINDOWS}
    function ThreadWrapper(Parameter: Pointer): Integer; stdcall;
    {$ELSE}
    function ThreadWrapper(Parameter: Pointer): Pointer; cdecl;
    {$ENDIF}
    asm
    {$IFDEF PC_MAPPED_EXCEPTIONS}
            { Mark the top of the stack with a signature }
            PUSH    UNWINDFI_TOPOFSTACK
    {$ENDIF}
            CALL    _FpuInit
            PUSH    EBP
    {$IFNDEF PC_MAPPED_EXCEPTIONS}
            XOR     ECX,ECX
            PUSH    offset _ExceptionHandler
            MOV     EDX,FS:[ECX]
            PUSH    EDX
            MOV     FS:[ECX],ESP
    {$ENDIF}
    {$IFDEF PC_MAPPED_EXCEPTIONS}
        // The signal handling code in SysUtils depends on being able to
        // discriminate between Delphi threads and foreign threads in order
        // to choose the disposition of certain signals.  It does this by
        // testing a TLS index.  However, we allocate TLS in a lazy fashion,
        // so this test can fail unless we've already allocated the TLS segment.
        // So we force the allocation of the TLS index value by touching a TLS
        // value here.  So don't remove this silly call to AreOSExceptionsBlocked.
            CALL    AreOSExceptionsBlocked
    {$ENDIF}
            MOV     EAX,Parameter        MOV     ECX,[EAX].TThreadRec.Parameter
            MOV     EDX,[EAX].TThreadRec.Func
            PUSH    ECX
            PUSH    EDX
            CALL    _FreeMem
            POP     EDX
            POP     EAX
            CALL    EDX{$IFNDEF PC_MAPPED_EXCEPTIONS}
            XOR     EDX,EDX
            POP     ECX
            MOV     FS:[EDX],ECX
            POP     ECX
    {$ENDIF}
            POP     EBP
    {$IFDEF PC_MAPPED_EXCEPTIONS}
            { Ditch our TOS er }
            ADD     ESP, 4
    {$ENDIF}
    end;
     看過這段沒,匯編不太好,感覺像在處理無類型的參數的。看來DELPHI本身是處理了的。
      

  16.   

    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;type
      TForm1 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        procedure Button1Click(Sender: TObject);
       // procedure FormCreate(Sender: TObject);
       // procedure Button1Click(Sender: TObject);
        //procedure Button2Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;function threadfunc(StartPos: pointer):integer ;stdcall;  //
    implementation{$R *.dfm}function threadfunc(StartPos: pointer):integer ;stdcall;  //
    var
    s,i:integer;
    begin
    i:=0;
    try
    s := s div i;
     Result := S;
    exceptend;
    end      ;
    procedure TForm1.Button1Click(Sender: TObject);
    var
    cThreadId,cThreadId2 :cardinal;
    begin
      CreateThread(nil,1024,@threadfunc,nil,0,cThreadId2);  // 不要再用DELPHI封裝的 BeginThread  了,用 Window 的 createThread  就OK了。
    end;end.
      

  17.   

    已经基本可以结贴了,谢谢各位,尤其是starluck 和 jadeluo