d6的dll结束时候触发不了结束的事件代码,很奇怪,我也问过!没人知道!d5就没有问题!

解决方案 »

  1.   

    你的TMyThread.FreeOnTerminated 是不是 False(default是False),如果是False,那线程结束后并不Free对象,那么也不会触发你的myEvent了。看是不是这个问题。
      

  2.   

    回去看了一下,发现不是上面所说的问题,不知你是怎么写它的onTerminate事件的constructor TMyThread.Create(CreateSuspended: Boolean);
    begin
      OnTerminate := Form1.OnThreadExit;
      inherited Create(CreateSuspened);
    end;如果你的CreateSuspended是False,将那事件写在构造函数中,如果是True,那可以写在
      FThread := TMyThread.Create(True);
      FThread.OnTerminate := OnThreadExit;
      FThread.Resume;
      

  3.   

    楼上说的我都做过,但都是不能解决问题。最后我采取了一个办法就是在dll的主窗体里面
    我重载了wndproc消息处理方法,加入了一个函数  CheckSynchronize(这个函数是通过分析D6的Theard线程类找到的,它的作用是检查当前访问VCL组件的线程是否已经结束)这个函数加入后,线程可以结束并被DLL窗体捕获,但是新问题又产生了,就是在产生一个新线程以后,如果这个时候你什么都不做,鼠标、键盘都不在DLL主窗体中做任何操作,那么这个线程还是不会引发完成事件,wndproc好像没有起作用。但只要你的鼠标或者键盘在DLL主窗体中动一下,产生一个窗口消息、wndproc好像开始工作,进入消息循环,线程结束事件引发。
        程序单步执行的话没有上述问题。恳请高手指点,不甚感激!附:wndproc
    procedure TfrmMp3Tag.WndProc(var Msg: TMessage);
    var
      // IconID:integer;
       pt:TPOINT;
    begin   if msg.Msg = WM_TRAYNOTIFY then
         begin
         //在通知消息中,wParam参数为图标的uID,lParam参数为鼠标事件的类型。
        // IconID:= msg.WParam;
         //获取鼠标的在屏幕上的位置
         GetCursorPos(pt);
         //通知消息的处理的基本框架结构如下:
         case msg.lParam of
              WM_LBUTTONDOWN:
              begin
              //鼠标左键被按下
              //ShowMessage('Test!');
              end;
              WM_RBUTTONDOWN:
              begin
              //鼠右键被按下
              PopTray.Popup(pt.X,pt.Y);
              end;
              WM_LBUTTONUP:
              begin
              //释放鼠标左键
              end;
              WM_RBUTTONUP:
              begin
              //释放鼠标右键
              end;
              WM_MOUSEMOVE:
              begin
              //鼠标在图标上移动
              end;
              WM_LBUTTONDBLCLK:
              begin
              //鼠标左键双击
                frmMp3Tag.show;
              end;
              WM_RBUTTONDBLCLK:
              begin
              //鼠标右键双击
              end;
           end; //end case
          end
          else 
          begin
             CheckSynchronize;//注意本函数
             inherited;
          end;
        end;
      

  4.   

    你把线程调用和它的execute主要部分写出来看看吧。
    WndProc只是处理有消息,没消息当然不会处理,如果你想要处理线程的Synchronize的东西,给Application发一个WM_NULL(Delphi6)消息就行了。
      

  5.   

    Delphi5和Delphi6的线程不同就是在Synchronize上,D5是另开一个Handle,D6是通过发一个消息给Application.Handle,比较符合同步的意思。
      

  6.   

    我不太清楚你的线程中是怎么用的,这是我对D6线程的看法,希望对你有帮助。Classes.pasvar
      WakeMainThread: TNodifyEvent = nil;在D6 Thread中使用Synchronize方法,因为它是调用WakeMainThread方法来实现,而在普通的Application中WakeMainThread是被赋值了的,对应是Application.WakeMainThread, 而当你如果你是写DLL, Form, 虽然它有Application,但是它不同于你的调用的Application,我试了一下,将一个普通Application,调用一个DLL中的Application,它们的Handle和Address是不相同的,
    也就是说在DLL中如果你调用线程中的Synchronize方法,那么它会失败,甚至于会引起错误或一直阻塞线程,原因就是DLL中Classes.WakeMainThread没有给赋值,然后线程却一直在阻塞进程的运行(wait for), 
    情况差不多是这样:
     
    procedure TMyThread.Execute;
    begin
      ...
      Synchronize(SomeThing);
      ...
    end;procedure TThread.Synchronize(Method: TThreadMethod);
    var
      SyncProc: TSyncProc;
    begin
      SyncProc.Signal := CreateEvent(nil, True, False, nil);
      ...
      FMethod := Method;
      SyncProc.Thread := Self;
      SyncList.Add(@SyncProc);
      if Assigned(WakeMainThread) then //DLL中它是没有值的。一直执行到waitfor
        WakeMainThread(Self);//如是普通Application,那么它会去调用CheckSynchronize,将SyncProc.Signal进行置位,那下面的WaitFor函数会马上返回
      LeaveCriticalSection(ThreadLock);
      try
        WaitForSingleObject(SyncProc.Signal, INFINITE);  //好了,阻塞进程了,你这线程完了,INFINITE是无限长时间,这线程一直等到天亮SyncProc.Signal只有处理了CheckSynchronize才会被置位。哈哈。
      finally
        EnterCriticalSection(ThreadLock);
      end;
      ...
    end;所以如果想在你的DLL中进行VCL组件同步,你必须写自己的WakeMainThread过程,像Application那样。
      
    constructor TDLLForm.Create(AOwner: TComponent);
    begin
      Classes.WakeMainThread := WakeMainThread;
      inherited Create(AOwner);
    end;TDLLForm.WndProc(var Msg: TMessage);
    begin
      case Msg.Msg of
        ...
        WM_NULL: CheckSynchronize;
      end;
    end;procedure TDLLForm.WakeMainThread(Sender: TObject);
    begin
      PostMessage(Handle, WM_NULL, 0, 0); 
      //or直接调用同步。那在WndProc就不用再处理WM_NULL消息了。
      //CheckSynchronize;
    end;因为在普通Application中还有一个原因它会调用CheckSynchronize,就是当PeekMessage不了消息时(没有消息时,空闲时候),也会调用它,这一步就不好做了,你的DLLForm是不会去PeekMessage,只有你的线程才会去PeekMessage,而线程的PeekMessage只是对自己线程消息(GetCurrenThreadID)有效,你可以试试在DLLForm中加一个TTimer,定时给自己发消息,像作Idle事件处理.