C# 向指定线程发送消息

线程间通信,包括线程同步,在指定线程中执行方法。

线程同步

其中线程同步通过C#本身提供的线程操作还是比较简单的,注意使用互斥锁,WaitHandle的使用可以满足大部分的需求。(互斥锁在不同线程中起作用,不会堵塞同线程的程序运行)。


在指定线程中执行方法

这种情况比较少见,一般都是窗体程序需要后台进行运算,通过运算的结果对前台界面进行更新。大多数情况下使用BackgroundWorker类和Task类可以满足需求。但在极端的情况下可能还是需要自己去实现不同线程的方法执行。

C#本身的线程操作中不能直接做到在一个线程中让另一个特定的线程运行方法,要完成这样的操作,需要用到Windows的消息机制。使用下面的函数可以向指定ID的线程发送消息:

BOOL WINAPI PostThreadMessage(
  _In_ DWORD  idThread,
  _In_ UINT   Msg,
  _In_ WPARAM wParam,
  _In_ LPARAM lParam
);
在C#中可以用下面的方式引用方法

[DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool PostThreadMessage(int idThread, int Msg, IntPtr wParam, IntPtr lParam);

如果要向一个窗体的线程发送自定义消息,使用PostThreadMessage函数时会发现窗体无法接收到自己定义的消息。这是因为窗体进程的标准消息循环只获取对窗体发送的消息而PostThreadMessage只是指定了接收消息的线程ID,所以通过PostThreadMessage被过滤掉了。

如果接收消息的是有窗体的线程,可以用SendMessage函数向指定的窗体发送消息。

在必须指定线程ID的情况下,只能通过Hook来完成相关操作。

我选择的是WH_GETMESSAGE类型的HOOK,回掉函数为:

LRESULT CALLBACK GetMsgProc(
  _In_ int    code,
  _In_ WPARAM wParam,
  _In_ LPARAM lParam
);

其中 code 参数并不是消息的消息值。真正的消息值要通过lParam来获得,lParam指向一个MSG结构。

同时一个相同的消息一般会被接收到2次,一次在消息还在消息队列中时接收一次,另一次是消息从消息队列中被移除。

通过wParam的值可以知道当前捕获的消息是否在队列中。

你可能感兴趣的:(研发技术)