• Delphi7从子线程中发送消息到主线程触发事件执行


    【转载】Delphi7从子线程中发送消息到主线程触发事件执行
    
     
    
    在对数据库的操作时,有时要用一个子线程来进行后台的数据操作。比如说数据备份,转档什么的。在主窗口还能同是进行其它操作。而有时后台每处理一个数据文件,要向主窗口发送消息,让主窗口实时显示处理进度在窗口上(可视),同时进行日志处理等。我用的是下面的方法:
    
    [1]用到的API函数:
    RegisterWindowsMessage
    ----------------------
    函数功能:该函数定义一个新的窗口消息,该消息确保在系统中是唯一的。返回的消息值可在调用函数SendMessage或PostMessage时使用。
    function RegisterWindowMessage(lpString: PChar): UINT; stdcall;
    
    SendNotifyMessage
    ----------------------
    函数功能:该函数将指定的消息发送到一个窗口。
          如果该窗口是由调用线程创建的;此函数为该窗口调用窗口程序,
          并等待窗口程序处理完消息后再返回。
          如果该窗口是由不同的线程创建的,此函数将消息传给该窗口程序,
          并立即返回,不等待窗口程序处理完消息。
     SendNotifyMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);
    
    BroadcastSystemMessage
    ----------------------
    函数功能:该函数发送消息给指定的接受者。
          接受者可以是一个应用程序、安装驱动器、网络驱动器、系统级设备驱动器
          或这些系统组件的组合。
    
    [2]过程:
     type
      TForm1 = class(TForm)
            ...............
            ...............
      private
        Msg: Cardinal;
      protected
        procedure WndProc(var Message: TMessage); override;
      public
            ...............
            ...............
      end;
    
     var
      Form1: TForm1;
      MsgStrList: TStringList;
      MsgStrLock : TCriticalSection;
    
    implementation
    uses ThreadCommunication_Unit;
    {$R *.dfm}
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      Msg := RegisterWindowMessage('wm_threadmsg');
      MsgStrList := TStringList.Create;
    end;
    
    procedure TForm1.WndProc(var Message: TMessage);
    begin
      if Message.Msg = Msg then begin
        MsgStrLock.Enter;
        if MsgStrList.Count > 0 then begin
          Caption := MsgStrList.Strings[0];
          MsgStrList.Delete(0);
        end;
        MsgStrLock.Leave;
        ShowMessage('收到消息了'+ inttostr(Message.Msg));
      end
      else begin
        inherited;
      end;
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      TThreadCommunication.Create(Msg,Memo1);
    end;
            ...............
            ...............
    
    initialization
      MsgStrLock := TCriticalSection.Create;
    finalization
      MsgStrLock.Free;
    end.
    
    一个子线程类的单元:
    unit ThreadCommunication_Unit;
    interface
    
    uses
      Classes,StdCtrls;
    
    type
      TThreadCommunicaiton = class(TThread)
      private
        FMsg : Cardinal;
        FMemo: TMemo;
      protected
        procedure Execute; override;
        procedure SendMsg;
      public
        constructor Create(aMsg:Cardinal;am:TMemo);virtual;
      end;
    
    implementation
    uses Messages,Windows, Dialogs,SysUtils, ThreadMsg;
    
    { TThreadCommunicaiton }
    
    constructor TThreadCommunicaiton.Create(aMsg: Cardinal; am:TMemo);
    begin
      inherited Create(True);
      FMsg := aMsg;
      FMemo:= am;
      FreeOnTerminate :=True;
      Resume;
    end;
    
    procedure TThreadCommunicaiton.Execute;
    begin
      Synchronize(SendMsg);
    end;
    
    
    procedure TThreadCommunicaiton.SendMsg;
    var
      M: TMessage;
      B: DWord;
      d: integer;
    begin
      { Place thread code here }
      sleep(50);
      M.Msg := FMsg;
      B := BSM_ALLCOMPONENTS;
    
      MsgStrLock.Enter;
      MsgStrList.Add('子线程子柄:'+inttostr(ThreadID)+ ' 用BroadcastSystemMessage发送');
      d := MsgStrList.Count;
      MsgStrLock.Leave;
    
      BroadcastSystemMessage(BSF_POSTMESSAGE, @B , M.Msg, M.WParam, M.LParam );
      FMemo.Lines.Add('子线程子柄:'+inttostr(ThreadID)+ ' 用BroadcastSystemMessage发送'+inttostr(d));
    
    end;
    
    end.
    
    我在窗口上放有一Memo控件,可以显示一些信息。
    同时我定义了一个全局的TStringList的变量,用于存在要从子线程传出的一些值。用BroadcaseSystemMessage发送消息,而消息号由创建子线程时传入。而消息号在FormCreate中用RegisterWindowsMessage定义,并获得一个消息号。
    而消息触发后的事件处理写在WndProc中。
    这里将子线程传出的字符串写入窗口的标题。
    
    而TStringList的变量作为临界区使用, 因为当两个线程访问全局量时,为防止它们同时执行,需要使用线程同步。
    
    用TCriticalSection进行操作。
    Enter,进入临界区
    Leave,离开临界区
    这样可以正确的处理从子线程发来的消息。
    
    如果是用SendNotifyMessage函数发送消息的话。
    用法如下:
      M.Msg := FMsg;
      SendNotifyMessage(HWND_BROADCAST,M.Msg , M.WParam, M.LParam);
    
    参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。
    
    由于是用SendNotifyMessage将消息发送到主窗口,而主窗口所在线程与调用线程是同一个线程,所以要等待窗口程序处理完消息后再返回。才会执行子线程中的:
    
    FMemo.Lines.Add('子线程子柄:'+inttostr(ThreadID)+ ' 用SendNotifyMessage发送');
    
     
    
    还可以用
     function PostMessage(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): BOOL; stdcall;
    hWnd是窗口句柄,你可以将消息发送到主窗口。
    而SendNotifyMessage是将消息发送到所有的顶层窗口。就是说如果你在系统中启动了两个实例运行。
    一个中发出的消息两个实例都会收到。而PostMessage由于是对句柄发消息。只会在本身这个实例中产生作用。
  • 相关阅读:
    odoo API装饰器one、model、multi的区别
    odoo配置界面设置字段默认值
    redhat_6.5下载地址
    常用在线工具链接
    odoo开发环境搭建(四):python开发工具IDE pycharm配置
    odoo开发环境搭建(三):安装odoo依赖的python包
    odoo开发环境搭建(二):安装Ubuntu 17虚拟机
    odoo开发环境搭建(一):安装VMware Workstation
    火狐浏览器网页截屏插件
    copy代码的时候,如何去掉代码前边的编号
  • 原文地址:https://www.cnblogs.com/moonwind/p/4496591.html
Copyright © 2020-2023  润新知