没有合适的资源?快使用搜索试试~ 我知道了~
首页VC++实例详解-3(不可多得的MFC教程)
资源详情
资源评论
资源推荐

下载
第 3 章 通 信
在第1章中我们讨论了怎样使用 S e n d M e s s a g e ( ) 和P o s t M e s s a g e ( )函数与应用程序的窗口通
信。如果要与其他的应用程序或者另一个系统中的应用程序通信又该怎么去做呢?
本章将概述6种应用程序与外界通信的方法,其中包括与其他操作系统、 I n t e r n e t以及串行
线之间的通信。另外,还要探讨这些通信连接方式如何允许程序员控制其他的应用程序甚至
使用它们。此外还要介绍用于与其他应用程序共享大量数据的方法。
3.1 进程间通信
应用程序之间的通信,不管是在同一系统上或是通过网络进行,都叫做进程间通信 ( I P C :
Interprocess Communication)。M F C 应用程序为进程间通信准备了下列 6种可用的途径:
■ 窗口消息( Windows message),允许与其他应用程序的窗口通信。这与先前用于与自己
的应用程序窗口通信所采用的窗口消息是一个概念。
■ 动态数据交换(DDE: Dynamic Data Exchange),通过维护全局分配内存使得应用程序
间传递大量数据成为可能。其方式是在一块全局分配内存中手工放置大量的数据,然后使
用窗口消息传送该内存指针。 D D E 提供了一种标准使得任何遵守该标准的应用程序都可以
采用它。
■ 消息管道(Message Pipe),用于设置应用程序之间的一条永久通信通道,通过该通道
可以像自己的应用程序访问一个平面文件一样读写数据。 D D E 的数据传送速度使人失望,
但是采用消息管道就可以无缝地发送数据到其他应用程序,而这些应用程序可能在其他系
统上。
■ Wi n d o w s套接字( Windows Socket),它具备消息管道的所有功能,但遵守一套通信标准
使得不同操作系统之上的应用程序之间可以互相通信。这些操作系统可以是非 Wi n d o w s 系统,
例如U N I X 系统。实际上在开发新的应用程序时,使用 Wi n d o w s套接字比消息管道和 D D E 都更
为有利。
■ I n t e r n e t 通信,它让应用程序从 I n t e r n e t 地址上载或者下载文件。
■ 串行/并行通信(Serial/Parallel Communication),它允许应用程序通过串行或者并行端口
与其他应用程序通信。
3.1.1 通信策略
虽然以上的每一种通信方式都是用不同的 Windows API或者M F C 类调用的,但是使用它
们的过程却大同小异:
1) 用Windows API或者M F C 类打开与其他应用程序之间的通信连接。
2) 读取或者写入对方应用程序。对某些方式而言可能意味着发送及接收消息。对另一些
方式,该过程则与读写普通文件没有太大的不同。
3) 关闭连接。

3.1.2 同步和异步通信
每一种通信方式都可以是同步或者异步的。同步 ( s y n c h r o n o u s ) 通信使应用程序暂停,直
到它完成对其他应用程序的读或者写操作。异步 ( a s y n c h r o n o u s )通信则允许应用程序继续运行,
当系统完成读写操作时就会用一个事件标记或者调用指定的函数通知用户任务已经完成。
虽然异步通信听起来更为适当,特别是在应用程序要一次同其他几个应用程序会话的情
况下更是如此,但这种方式并不是面向对象的。程序员不是需要跳出对象提供静态回调函数
就是需要费心处理事件标记。同时,设置异步连接也更为复杂,更容易产生程序错误 ( b u g ) 。
解决方案是采用同步通信,但要将每个读写操作放进它自己的线程中,这样这些操作就
不会再阻止应用程序之间的通信。当操作完成后,线程可以自动地将读取的数据存回应用程
序。当然,它也可以设置事件标记,但这需要在更为友好的 M F C 类的环境下才可以。实例 5 1
和实例5 2 说明了怎么做到这一点。
注意 应用程序创建自己线程的能力只有Windows 95和Windows NT操作系统才具备。
如果是在Windows 3.1系统平台上开发,就需要使用异步通信。对异步通信来说,操作
系统本身将读写操作放进了自己的特定线程。
注意 用Wi n d o w s 套接字的术语来说:同步通信的应用程序被认为是阻塞 ( b l o c k i n g )类
型的。
下面研究以上的每一种通信方式,其中包括如何打开和关闭通信连接以及如何利用连接
进行读写操作。
3.2 窗口消息
先前所述的窗口消息系统允许应用程序控制其窗口并处理来自用户的命令消息,这套消
息系统同样可以用于控制并处理来自其他应用程序的命令。正是由于全局分配每个窗口对象
才使得这一切成为了可能,这样任何应用程序都能够发送消息到其他应用程序窗口。关键在
于必须知道要同哪个窗口对话。
3.2.1 打开和关闭
打开与其他应用程序之间的通信连接,涉及到确定应用程序要发送消息到某个窗口所对
应的窗口句柄。麻烦在于,因为每个句柄不是在编译或者链接应用程序时创建而是在窗口被
创建的时候才生成,所以每次运行时都有可能不同。这样就不能知道该句柄。而且,也不可
能询问其他窗口其句柄是什么。因为正是需要那些窗口的句柄才可能发出这一请求!这里有 3
种技术可以得到其他窗口句柄:
■ 当一个父应用程序创建其子应用程序的时候,它将属于自己的一个窗口的句柄作为参
数传送。子应用程序然后可以将该句柄发送给自己的一个窗口句柄,这样通信就可以进行了。
一般情况下,这些应用程序之间交换的句柄都是普通句柄,但总是被创建为只进行通信的窗
口所隐藏。关闭连接也就只是关闭这些窗口。
■ 但是,如果目标应用程序已经在运行了,则可以调用 Windows API函数: F i n d Wi n d o w ( )
以找到适当的窗口。该函数将返回一个句柄,该句柄指向任何匹配特定的名字或者使用了特
定的窗口类的窗口。为了帮助 F i n d Wi n d o w ( )函数发现正确的窗口,可以用唯一的名字或者
44第第第一部分第基第第础
下载

Windows 类创建如上所述的普通消息窗口。
■ 得到正确窗口句柄的最后一种方式是采用 Windows API函数B r o a d c a s t S y s t e m M e s s a g e
( ),该函数将发送一个消息给每一个当前正在运行的应用程序。使用 B r o a d c a s t S y s t e m M e s s a g e
( ) 函数可以广播包含自己应用程序窗口句柄的特定消息,处理该消息的应用程序则随后以其句
柄作为答复,从而完成这个循环。请参考实例 4 9 来了解该方法。
3.2.2 读与写
到现在为止,与其他应用程序通信已经成为一件并不复杂的事情了,所要做的仅仅是将
窗口句柄插入: : S e n d M e s s a g e ( )或者: : P o s t M e s s a g e ( )之中。还可以用 A t t a c h ( )函数将窗口句柄封
装到C W n d类中,然后利用 C W n d的其他方法来发送和寄送消息。发送消息向应用程序提供了
同步通信,寄送消息则提供异步通信。
虽然一般情况下需要向目标窗口发送标准的窗口消息 (如W M _ C L O S E,W M _ M O V E等),
但有时也要创建自己的窗口消息来完成某些特定任务。
可以在W M _ U S E R以上范围内定义消息来创建自己的窗口消息 I D 。如下所示:
#define WM_MYMESSAGE WM_USER + 1
但是,创建新窗口消息I D的更可靠的方法是向系统注册自己的消息,如下所示:
#define IDString "MyMessage"
MsgID = ::RegisterWindowMessage( IDString );
这里I D S t r i n g 是每个应用程序都关注的唯一文本字符串,M s g I D是要创建的消息I D。因此,
这种方式比为自己的消息 I D分配数值而可能引起应用程序内部的混乱效果要好。另外还可以
用描述字符串如O p e n F i l e和: : R e g i s t e r Wi n d o w M e s s a g e ( )函数来创建自己的消息I D 。如果某应用
程序抢先注册了 O p e n F i l e ,接下来使用 O p e n F i l e 的应用程序就可以调用 : : R e g i s t e r
WindowMessage ()返回同样的消息I D ,因此不会有混淆的危险。
请参考实例4 9 了解如何正确使用这些函数。
3.2.3 回顾
利用窗口消息向其他应用程序发送消息实际上是先得到其他应用程序句柄,然后向其发
送消息。请参见图3 - 1 回顾全过程。
图3-1 窗口消息发送
第 3 章第通第第信第第45
下载
应用程序A通过使
用: : F i n d Wi n d o w ( ) 来搜
索或者直接从应用程
序B获得窗口1的句柄
应用程序A使用
S e n d M e s s a g e ( ) 或
P o s t M e s s a g e ( ) 将消
息发送给该窗口句柄
应用程序
A
窗口
1
应用程序
B
窗口1可以是应用程序 B的
主窗口,也可以是仅用于
通信的隐藏窗口
窗口1可以通过在应用程
序B中保存数据或控制应
用程序B来处理该消息

3.3 动态数据交换
S e n d M e s s a g e ( ) 和P o s t M e s s a g e ( )函数允许同时向其他应用程序发送两个整型数值。因此传
送1 0 0 0个字节就需要2 5 0 个消息。为了一次发送更多消息,可以将数据填满一块全局分配内存
并将其句柄作为参数之一传送。这种方式仅允许同自己设计的其他应用程序交换数据。为了
与非自己设计的应用程序交换数据就要采用 DDE(Dynamic Data Exchange)的标准,该方法已
经在动态数据交换库( D D E M L )中实现。
3.3.1 客户/服务器
D D E 的采用引进了客户应用程序和服务器应用程序 ( C l i e n t / S e r v e r ) 的概念。在D D E 的情况
下,几乎所有的数据都驻留在服务器上供客户应用程序来访问。此时的通信方式可以形容为:
服务器打出一块牌子,上面写着“对外办公”,客户则从服务器读写数据。
客户/服务器通讯方式将在以后章节详细讨论。
3.3.2 打开和关闭
为了打开通信连接,服务器应用程序通过广播自己的方式开始启动,程序如下所示:
// initialize DDE services
UINT DdeInitialize(
LPDWORD pidInst, // a pointer to the instance
PFNCALLBACK pfnCallback, // a callback function (see below)
DWORD afCmd, // command and filter flags
DWORD ulRes // reserved
) ;
// create a string handle to the name of the service we are creating
HSZ DdeCreateStringHandle(
DWORD idInst, // returned by DdeInitialize() above
LPTSTR psz, // pointer to service name string
int iCodePage // CP_WINANSI or CP_WINUNICODE for Unicode
) ;
// register the service
H D D E D ATA DdeNameService(
DWORD idInst, // returned by DdeInitialize() above
HSZ hsz1, // string handle to service name
0 L , // reserved
UINT afCmd // service name flags
) ;
然后客户应用程序如下连接到服务器:
UINT DdeInitialize( ... ); // as seen above
HCONV DdeConnect(
DWORD idInst, // returned by DdeInitialize() above
HSZ hszService, // handle to service name string
HSZ hszTo p i c , // handle to topic name string (optional)
PCONVCONTEXT pCC // pointer to structure with context data
) ;
为了在服务器应用程序中处理该连接,服务器的回调函数必须处理一个 X T Y P _
46第第第一部分第基第第础
下载
剩余19页未读,继续阅读












安全验证
文档复制为VIP权益,开通VIP直接复制

评论1