VC 6.0下利用消息实现内部进程通讯

引言

内部进程间通讯和数据交换有消息、共享内存、匿名(命名)管道、邮槽、Windows套接字等多种技术。其中利用消息机制实现IPC虽然同其他方法相比有交换的数据量小、携带的信息少等缺点,但由于其实现方便、应用灵活而广泛应用于无须大量、频繁数据交换的内部进程通讯系统之中,尤其是对于在上层主控软件与底层工作软件之间的命令与响应上更能充分显示其良好的性能。本文就通过编制一个主控软件和一个受其操作的底层工作软件来阐述如何用VC++6.0通过消息来实现内部进程通信。

Windows消息机制

  Windows是一种面向对象的体系结构,Windows环境和应用程序都是通过消息来交互的。Windows应用程序开始执行后,Windows为该程序创建一个“消息队列(message queue)”,用以存放邮寄给该程序可能创建的各种不同窗口的消息。消息队列中消息的结构(MSG)为:

typedef struct tagMSG{

HWND hwnd;

UINT message;

WPARAM wParam;

LPARAM lParam;

DWORD time;

POINT pt;

}MSG;

其中第一个成员变量是用以标识接收消息的窗口的窗口句柄;第二个参数便是消息标识号,如WM_PAINT;第三个和第四个参数的具体意义同message值有关,均为消息参数。前四个参数是非常重要和经常用到的,至于后两个参数则分别表示邮寄消息的时间和光标位置(屏幕坐标)。

把消息传送到应用程序有两种方法:一种是由系统将消息“邮寄(post)”到应用程序的“消息队列”这是“进队消息”Win32 API有对应的函数:PostMessage(),此函数不等待该消息处理完就返回;而另一种则是由系统在直接调用窗口函数时将消息“发送(send)”给应用程序的窗口函数,属于“不进队消息”对应的函数是SendMessage()其必须等待该消息处理完后方可返回。消息是在消息循环中被处理的,下面这段代码就是一个典型的消息循环:

hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_PRONOTE);

// Main message loop:

while (GetMessage(&msg, NULL, 0, 0)) 

{

if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

return msg.wParam;

     消息循环以GetMessage调用开始,它从消息队列中取出一个消息。该函数的四个参数可以有控制地获取消息,第一个参数指定要接收消息的MSG结构的地址,第二个参数表示窗口句柄,一般将其设置为空,表示要获取该应用程序创建的所有窗口的消息;第三、四参数用于指定消息范围。后面三个参数被设置为默认值,用于接收发送到属于这个应用程序的任何一个窗口的所有消息。在接收到除WM_QUIT之外的任何一个消息后,GetMessage()返回TRUE;如果GetMessage收到一个WM_QUIT消息,则返回FALSE以退出消息循环,终止程序运行。因此,在接收到WM_QUIT之前,带有GetMessage()的消息循环可以一直循环下去。

当除WM_QUIT的消息用GetMessage读入后,首先要经过函数TranslateMessage()对其进行解释,但对大多数消息来说并不起什么作用。这里起关键作用的是DispatchMessage()函数,把由GetMessage获取的Windows消息传送给在MSG结构中为窗口所指定的窗口过程。在消息处理函数处理完消息之后,代码又循环到开始去接收另一个消息,这样就完成了一个完整的消息循环。

主控程序的实现

  本文将设计一个主控程序和一个底层工作程序,由主控程序通过消息来控制底层工作程序的工作状态。这里首先对主控程序的设计过程进行介绍:

  首先创建一个单文档工程,添加三个菜单“命令一”、“命令二”、“命令三”及与之对应的命令响应函数:

OnSendComm1()

{

CString str="Receiver";

CWnd *pWnd=CWnd::FindWindow(NULL,str);

if(pWnd)

pWnd->SendMessage(WM_COMM,0,0);

}

OnSendComm2()

{

CString str="Receiver";

CWnd *pWnd=CWnd::FindWindow(NULL,str);

if(pWnd)

pWnd->SendMessage(WM_COMM,0,1);

}

OnSendComm3()

{

CString str="Receiver";

CWnd *pWnd=CWnd::FindWindow(NULL,str);

if(pWnd)

pWnd->SendMessage(WM_COMM,1,0);

}

  这里,WM_COMM是自定义消息,用于在主控程序和底层通信程序之间进行联系,为了能够使用该消息,必须首先添加预定义语句:

#define WM_COMM WM_USER + 100

上述几个函数的结构没有什么区别,首先通过FindWindow()返回由str变量指定窗口标题的应用程序主窗口句柄并将其保存到pWnd。然后再通过该句柄调用SendMessage()函数并发送刚才定义的WM_COMM消息及其消息参数。如果函数被正确执行,底层程序将收到来发自主控程序的WM_COMM消息并可在消息响应函数中完成对消息参数的判断处理以及进一步的操作。

底层工作程序的实现

  最后,来介绍一下底层工作程序的实现过程。底层工作程序也是一个单文档应用程序(当然,对于多文档应用程序也是一样)。由于主控程序是通过对应用程序主窗口标题的捕获来得到底层程序主窗口句柄的。因此需要在底层工作程序应用类的初始化应用函数InitInstance()中添加(在函数末尾添加)下面语句:

m_pMainWnd->SetWindowText("Receiver");

  以设置底层工作程序的窗口标题。同时还要在主框架类的头文件MainFrm.h中添加与主控程序一样的自定义消息定义:

#define WM_COMM WM_USER+100

  由于底层程序需要接收并响应主控程序发出的通知消息,因此还要在底层工作程序中添加对自定义消息WM_COMMAND的响应处理:

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

//{{AFX_MSG_MAP(CMainFrame)

// NOTE - the ClassWizard will add and remove mapping macros here.

// DO NOT EDIT what you see in these blocks of generated code !

ON_WM_CREATE()

//}}AFX_MSG_MAP

ON_MESSAGE(WM_COMM,OnSendMsg)

END_MESSAGE_MAP()

……

void CMainFrame::OnSendMsg(WPARAM wParam, LPARAM lParam)

{

if(wParam==0 && lParam==0)

AfxMessageBox("主控程序发送命令一!");

if(wParam==0 && lParam==1)

AfxMessageBox("主控程序发送命令二!");

if(wParam==1 && lParam==0)

AfxMessageBox("主控程序发送命令三!");

}

  此后就可以通过辨别消息的两个消息参数来区分主控程序发送的是哪一个命令从而可以执行相应的操作。执行主控程序和底层工作程序由于本程序采用的是SendMessage()所以当主控程序发送消息给底层工作程序时,底层工作程序弹出响应的模式对话框,在没有关闭对话框前此消息未处理完,SendMessage()也就没有执行完,所以主控程序呈阻塞状态,如改用PoseMessage()则不会发生阻塞,具体选用哪个函数还应根据实际要求灵活掌握。

结论: 

通过上面的实例可以看出利用消息进行进程间通信不失为一种便捷的方法,进程间的数据交换量不大却能完成相当的功能,上下层次有着明显的接口,上层和底层只通过这个接口进行通讯,因此只要对上下层程序制定好规范详尽的协议便可编制出协调性很好的软件控制系统。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容