zoukankan      html  css  js  c++  java
  • 【转载】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由于是对句柄发消息。只会在本身这个实例中产生作用。

  • 相关阅读:
    leetcode 78. 子集 JAVA
    leetcode 91. 解码方法 JAVA
    leetcode 75. 颜色分类 JAVA
    leetcode 74 搜索二维矩阵 java
    leetcode 84. 柱状图中最大的矩形 JAVA
    last occurance
    first occurance
    classical binary search
    LC.234.Palindrome Linked List
    LC.142. Linked List Cycle II
  • 原文地址:https://www.cnblogs.com/zhangzhifeng/p/6197485.html
Copyright © 2011-2022 走看看