IPC via Message Queue APIs in Windows Mobile 6.5

In Windows Mobile 6.5, the Point-to-Point Message Queue (MsgQueue) APIs provided a dedicated, lightweight inter-process communication (IPC) mechanism designed to pass data reliably between distinct processes or between user-mode applications and device drivers. Built upon the Windows Embedded CE 6.0 kernel, these APIs allowed developers to create synchronized, kernel-managed FIFO (First-In, First-Out) data pipelines. This architecture eliminated the risks of direct cross-process memory access while ensuring low latency and predictable performance on resource-constrained mobile hardware.

Architectural Context of Windows Mobile 6.5

Windows Mobile 6.5 utilized the Windows Embedded CE 6.0 kernel, which introduced a fully 32-bit virtual memory model supporting up to 32,000 concurrent processes, each with a private 2 GB virtual address space. Because processes were strictly isolated from one another to ensure system stability, direct pointer sharing was prohibited.

To overcome this isolation without the heavy overhead of COM or network-based sockets, the operating system exposed Point-to-Point Message Queues. Unlike traditional desktop Windows message queues tied to window handles (HWND) and user interface threads, Point-to-Point Message Queues were headless, data-centric, and managed directly by the kernel.

Core Message Queue APIs

The Point-to-Point Message Queue interface relied on a small, specialized set of C/C++ Win32 functions:

  • CreateMsgQueue: Initializes a new message queue. The creating process defines the queue attributes using the MSGQUEUEOPTIONS structure, specifying properties such as whether the queue is for reading or writing, the maximum number of messages, the maximum allowed message size, and whether the queue is named.
  • OpenMsgQueue: Allows a client process to obtain a handle to an existing named message queue created by another process, specifying desired access rights (read or write).
  • WriteMsgQueue: Inserts a data packet into the target queue. It allows the caller to specify a timeout interval, dynamic buffer size, and message priority.
  • ReadMsgQueue: Extracts a message from the queue into a local memory buffer. Like the write operation, it supports configurable timeouts and tracks message flags.
  • CloseMsgQueue: Releases the handle to the queue and cleans up kernel resources when all handles are closed.

How IPC Was Established

Point-to-Point Message Queues operated primarily in a unidirectional fashion. Full-duplex communication required establishing two separate queues: one for outgoing requests and one for incoming responses.

  1. Queue Creation: The server process called CreateMsgQueue, passing a globally identifiable string name and configuring the bReadAccess flag to TRUE. The kernel allocated memory buffers for the queue inside the kernel address space.
  2. Queue Connection: The client process called OpenMsgQueue, targeting the same queue name and setting the bReadAccess flag to FALSE (indicating write access).
  3. Data Marshalling: When the client invoked WriteMsgQueue, the kernel copied the message payload out of the client's virtual memory space directly into the kernel's message buffer.
  4. Data Retrieval: When the server invoked ReadMsgQueue, the kernel copied the buffered data from kernel space into the server's target buffer.

Because the kernel handled the copying of data between disjoint address spaces, applications did not need to coordinate complex shared-memory mappings via CreateFileMapping or manually marshal pointers.

Synchronization and Event-Driven Processing

A critical advantage of the Point-to-Point Message Queue implementation was its integration with standard Win32 synchronization primitives. Queue handles acted as waitable kernel objects.

A reader process did not need to poll the queue continuously with ReadMsgQueue. Instead, it passed the queue handle directly to WaitForSingleObject or WaitForMultipleObjects. The kernel signaled the queue handle whenever a new message arrived, waking the reading thread immediately. If the queue filled to maximum capacity, write operations would automatically block until space became available or until an optional user-defined timeout expired, preventing memory exhaustion on physical mobile devices.