本文说明点对点消息队列 — 一个鲜为人知的 IPC 机制,它高效、灵活,并且专用于 Windows CE 4.0 及其更高版本。此外,本文还说明如何设计和使用托管包装,使 .NET Compact Framework 应用程序中的 IPC 极其简便。
开发人员能够以多种方式使用点对点消息队列。开发人员通常在无法宿主 .NET Compact Framework 运行库的情况下使用 IPC 作为替代方案(本机进程通过 IPC 与托管进程进行通讯),并且点对点消息队列是最佳选择。点对点消息队列还可以与操作系统进行交互,例如,用于获取电源信息。本文不介绍点对点消息队列的其他用途,这些用途留待您了解核心原理之后自行探究。
本部分以一个您易于了解的方式描述点对点消息队列函数。
当开发人员使用 IPC 时,一个进程创建用于写入的队列,另一个进程创建用于读取的队列 (CreateMsgQueue)。在双向 IPC 通讯中,开发人员在通讯的每一端(在两个独立的进程间或同一进程的两个对象间)都需要两个队列。
在使用点对点消息队列时,开发人员可以采用若干种方法。例如,有用于读取 (ReadMsgQueue)、写入 (WriteMsgQueue) 和关闭队列 (CloseMsgQueue) 的方法。此外,如果除了队列句柄之外,开发人员还具有拥有该队列的源进程的句柄,那么他们就可以打开现有队列 (OpenMsgQueue)。开发人员可以查询一些统计信息 (GetMsgQueueInfo),最后可以使他们的应用程序等待队列句柄 (WaitForSingleObject) 接收信号,以便确定队列中是否有数据。
打开一个现有队列时,开发人员只能指定一个选项 — 该队列是用于读还是用于写。当创建队列时,开发人员可以指定其他参数:名称 (lpszName) 和选项(类型为 MSGQUEUOPTIONS 的 lpOptions)。队列选项包括以下内容:单个消息的最大大小 (cbMaxMessage)、队列中消息的随机最大数量 (dwMaxMessages)、是否应该动态分配缓冲区(dwFlags、MSGQUEUE_NOPRECOMMIT),以及阅读器是否可以在没有编写器的情况下存在(dwFlags、MSGQUEUE_ALLOW_BROKEN),反之亦然。关闭队列时,开发人员将句柄作为参数 ( hMsgQ )。
写入队列需要一个指针 ( lpBuffer )、消息中的字节数 ( cbDataSize )、超时 ( dwTimeout ),以及该消息是否是一个警告消息( dwFlags 、MSGQUEUE_MSGALERT)。从队列读取需要:传入一个缓冲区 (lpBuffer)、缓冲区的大小 ( cbBufferSize ),以及一个超时值 ( dwTimeout );因此,可获悉实际字节数 ( lpNumberOfBytesRead ) 以及该消息是否为一个警告( pdwFlags 、MSGQUEUE_MSGALERT)。注意,超时是以毫秒计算的;0 表示“不阻塞”,而 INFINITE (-1) 表示“阻塞,直到操作完成或队列状态更改”。如果成功,读函数和写函数都返回 TRUE;否则,返回 FALSE。在后一种情况中,您可以获得扩展的错误信息 (GetLastError)。函数返回 FALSE 的可能原因有:缓冲区太小 (ERROR_INSUFFICIENT_BUFFER);没有编写器或阅读器,且开发人员未按前面段落中所述的那样指定 MSGQUEUE_ALLOW_BROKEN (ERROR_PIPE_NOT_CONNECTED);或者发生超时 (ERROR_TIMEOUT)。对于 WriteMsgQueue,如果未按前面段落中所述的那样指定 MSGQUEUE_NOPRECOMMIT,则也可能得到错误 ERROR_OUTOFMEMORY。
可调用 GetMsgQueueInfo 来获得包含统计信息的结构 (MSGQUEUEINFO)。该结构包含的信息包括开发人员在创建队列时传入的一些参数:消息的最大大小 (cbMaxMessage)、消息的最大数量 (dwMaxMessages)、是否应该动态分配缓冲区(dwFlags、MSGQUEUE_NOPRECOMMIT),以及阅读器是否可以在没有编写器的情况下存在(dwFlags、MSGQUEUE_ALLOW_BROKEN),反之亦然。此外,该结构还包含以下内容:当前队列中非警告信息的数量 (dwCurrentMessages)、队列中曾经存在消息的最大数量 (dwMaxQueueMessages)、当前阅读器的数量 (wNumReaders),以及当前编写器的数量 (wNumWriters)。