句柄线程做参数和PostMessage的用法

当我们启动一个线程,并且要给线程函数传递的参数是窗口句柄时,我们应该这样做:

HWND hHwnd = GetSafeHwnd();

HANDLE hThread;

DWORd dwThreadId;

hThread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)DeviceOnLine, (LPVOID)hHwnd, 0, &dwThreadId);

// DeviceOnLine是线程函数,原型static UINT DeviceOnLine(LPVOID pParam);

// 注意:参数的形式是这样的 (LPVOID)hHwnd,没有地址符,注意啊!为什么要传递的参数非得是句柄呢?(对啊,为什么?)应为我们要使线程函数和主线程通信,要使用PostMessage(...)函数,所以要谈到Windows的消息机制。

// -----------------------下面是Windows消息机制

Windows系统是一个消息驱动的OS,什么是消息呢?我很难说得清楚,也很难下一个定义(谁在嘘我),我下面从不同的几个方面讲解一下,希望大家看了后有一点了解。

1、消息的组成:一个消息由一个消息名称(UINT),和两个参数(WPARAM,LPARAM)。当用户进行了输入或是窗口的状态发生改变时系统都会发送消息到某一个窗口。例如当菜单转中之后会有WM_COMMAND消息发送,WPARAM的高字中(HIWORD(wParam))是命令的ID号,对菜单来讲就是菜单ID。当然用户也可以定义自己的消息名称,也可以利用自定义消息来发送通知和传送数据。

2、谁将收到消息:一个消息必须由一个窗口接收。在窗口的过程(WNDPROC)中可以对消息进行分析,对自己感兴趣的消息进行处理。例如你希望对菜单选择进行处理那么你可以定义对WM_COMMAND进行处理的代码,如果希望在窗口中进行图形输出就必须对WM_PAINT进行处理。

3、未处理的消息到那里去了:M$为窗口编写了默认的窗口过程,这个窗口过程将负责处理那些你不处理消息。正因为有了这个默认窗口过程我们才可以利用Windows的窗口进行开发而不必过多关注窗口各种消息的处理。例如窗口在被拖动时会有很多消息发送,而我们都可以不予理睬让系统自己去处理。

4、窗口句柄:说到消息就不能不说窗口句柄,系统通过窗口句柄来在整个系统中唯一标识一个窗口,发送一个消息时必须指定一个窗口句柄表明该消息由那个窗口接收。而每个窗口都会有自己的窗口过程,所以用户的输入就会被正确的处理。例如有两个窗口共用一个窗口过程代码,你在窗口一上按下鼠标时消息就会通过窗口一的句柄被发送到窗口一而不是窗口二。

5、示例:下面有一段伪代码演示如何在窗口过程中处理消息

LONG yourWndProc(HWND hWnd,UINT uMessageType,WPARAM wP,LPARAM)
{
        switch(uMessageType)
        {//使用SWITCH语句将各种消息分开
               case(WM_PAINT):
                       doYourWindow(...);//在窗口需要重新绘制时进行输出
               break;
               case(WM_LBUTTONDOWN):
                       doYourWork(...);//在鼠标左键被按下时进行处理
               break;
               default:
                       callDefaultWndProc(...);//对于其它情况就让系统自己处理
               break;
        }
}

接下来谈谈什么是消息机制:系统将会维护一个或多个消息队列,所有产生的消息都回被放入或是插入队列中。系统会在队列中取出每一条消息,根据消息的接收句柄而将该消息发送给拥有该窗口的程序的消息循环。每一个运行的程序都有自己的消息循环,在循环中得到属于自己的消息并根据接收窗口的句柄调用相应的窗口过程。而在没有消息时消息循环就将控制权交给系统所以Windows可以同时进行多个任务。下面的伪代码演示了消息循环的用法:

while(1)
{
        id=getMessage(...);
        if(id == quit)
               break;
        translateMessage(...);
}

当该程序没有消息通知时getMessage就不会返回,也就不会占用系统的CPU时间。 下图为消息投递模式

在16位的系统中系统中只有一个消息队列,所以系统必须等待当前任务处理消息后才可以发送下一消息到相应程序,如果一个程序陷如死循环或是耗时操作时系统就会得不到控制权。这种多任务系统也就称为协同式的多任务系统。Windows3.X就是这种系统。

而32位的系统中每一运行的程序都会有一个消息队列,所以系统可以在多个消息队列中转换而不必等待当前程序完成消息处理就可以得到控制权。这种多任务系统就称为抢先式的多任务系统。Windows95/NT就是这种系统。

// -------------------------------------------

不知道,你还记得那个线程函数吗?下面是定义

UINT DeviceOnLine(LPVOID pParam)
{
        HWND hHwnd = (HWND)pParam;    // 转化参数

...

CString str;

str.Format("test");

::PostMessage(hHwnd, WM_MY_MESSAGE, (WPARAM)str, NULL);   // 向hHwnd句柄PostMessage

// 要是static类型的,记住static函数的使用方法:一个版本,仅仅与类对话,没有this指针。

...

}

如果要使用PostMessage很多次,我们可以象下面这样独立出一个函数(由于我们是在static的线程函数里面使用,所以声明的也是static):

static int AddMessage(HWND hWnd, CString str)
 {
        if(str.GetLength() <= 0)
             return 0;
        char *newMess = new char[str.GetLength() + 1];
        strcpy(newMess,str);
        ::PostMessage(hWnd,WM_MY_MESSAGE,(WPARAM)newMess,0);
        return 0;
 }

现在,我们已经把我们需要的消息发了出去,那我们就还要处理它,不然我们还发它们干吗呢,呵呵(废话,快点说吧)!

首先:在类中声明处理函数,比如 afx_msg LRESULT AddMessageEx(WPARAM wPapam, LPAPAM lPapam);

其次:在Message Map中加入映射,比如:

BEGIN_MESSAGE_MAP(CTestDlg, CDialog)

ON_MESSAGE(WM_MY_MESSAGE, AddMessageEx)

END_MESSAGE_MAP

最后,实现处理函数:

LRESULT CTestDlg::AddMessageEx(WPARAM wParam, LPARAM lParam)
{
 char* newMsg = (char*)wParam;
 if(newMsg == NULL)
  return -1;
...    // 这里就可以使用我们接收的消息啦,哈哈!目的完成。

delete newMsg;
 return 0;
}

对了,还有一个比不可少的,就是在stdafx.h文件中加入,自己定义的消息

#define WM_MY_MESSAGE (WM_USER+123)

原文地址:http://blog.chinaunix.net/uid-20680966-id-1896390.html

*********************************以上是转载内容**************************************有空继续编辑**************************************************

时间: 2024-12-28 21:23:16

句柄线程做参数和PostMessage的用法的相关文章

如何向线程传递参数

Net提供了许多多线程编程工具,可能是因为太多了,所以掌握起来总是有一些头疼,我在这里讲讲我总结的一些多线程编程的经验,希望对大家有帮助 不需要传递参数,也不需要返回参数我们知道启动一个线程最直观的办法是使用Thread类,具体步骤如下 ThreadStart threadStart=new ThreadStart(Calculate); Thread thread=new Thread(threadStart); thread.Start(); public void Calculate()

C++ 中数组做参数的分析

C++ 中数组做参数的分析 1.数组降价问题? "数组引用"以避免"数组降阶",数组降阶是个讨厌的事,这在C语言中是个无法解决的问题,先看一段代码,了解什么是"数组降阶" 1 #include <IOSTREAM> 2 using namespace std; 3 4 void Test( char array[20] ) 5 { 6 cout << sizeof(array) << endl; // 输出 4

C++数组做参数

首先,看一下下面这段代码: void changearr(int a[],int n){    cout<<sizeof(a)<<endl;         // 输出4}int main(){    int a[10] = {2,78,100,88,12,55,45,0,1,2}; cout<<sizeof(a)<<endl;         // 输出40    changearr(a,10);    return 0;} 在C++中,数组名就是指向数组

以函数返回值做参数时,函数调用的顺序

环境:vs2013 在下面的代码中 1 //类似于下面的代码 2 3 foo(char*,char*,char*); 4 5 char* str ="A#B#C"; 6 7 foo(strtok(str,"#"),strtok(NULL,"#"),strtok(NULL,"#")); 预计让函数foo得到("A","B","C")的参数,程序编译的时候没问题,但是运行

Java基础-继承 利用接口做参数,写个计算器,能完成+-*/运算

38.利用接口做参数,写个计算器,能完成+-*/运算 (1)定义一个接口Compute含有一个方法int computer(int n,int m); (2)设计四个类分别实现此接口,完成+-*/运算 (3)设计一个类UseCompute,含有方法: public void useCom(Compute com, int one, int two) 此方法要求能够:1.用传递过来的对象调用computer方法完成运算 2.输出运算的结果 (4)设计一个测试类,调用UseCompute中的方法us

C++二维数组(指针)做参数

一.问题描述 使用C++编程过程中经常需要使用到二维数组,然而初级程序员在使用过程中经常会出错使程序崩溃.下面就二维指针的定义,初始化,以及二维指针做参数给出简单介绍. 1.二维数组的定义与初始化 在实际使用数组的时候往往开始不知道二维数组的行数和列数,因此程序需要根据用户输入动态定义二维数组的行和列.这里通过C++二级指针来实现,引入变量 int rowNum 行 数, int coluNum 列数, char **p 二维字符数组,这里假定二维字符数组中的字符只能为'0'和'1'. int

一个线程加一运算,一个线程做减一运算,多个线程同时交替运行--synchronized

使用synchronized package com.pb.thread.demo5; /**使用synchronized * 一个线程加一运算,一个线程做减法运算,多个线程同时交替运行 * * @author Denny * */ public class Count { private int num = 0; private boolean flag = false; // 标识 //加法 public synchronized void add() { while (flag) { tr

Linq中Lanbda表达式做参数

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Lanbda表达式做参数 { class Program { static void Main(string[] args) { int[] Array = new int[] { 3, 2, 4, 56, 6, 14, 53 }; Func<int, bool> mtDelB = delegate(in

【Simple Java】面试问题-使用Java线程做数学运算

这是一个展示如何使用join()方法的例子. 问题: 使用Java多线程计算表达式1*2/(1+2)的值. 解决方案: 使用一个线程做加法运算,另一个线程做乘法运算,还有一个主线程main做除法运算.由于线程之间不需要通讯,所以我们只需要考虑线程的执行顺序. 在main线程中,我们让加法运算线程和乘法运算线程join到主线程,join()方法的作用是使main方法等待,直到调用join的线程执行完毕.在这个例子中,我们希望加法运算线程和乘法运算线程先结束,然后在计算除法运算. package s