# The Application Kit: BMessenger

Derived from: none

Declared in: be/app/Messenger.h

Library: libbe.so

## Overview

A BMessenger is an agent for sending messages to a destination. Each BMessenger object targets a particular BLooper and possibly a specific BHandler for that BLooper. The messages it sends are delivered to the BLooper and dispatched by the BLooper to the BHandler. The destination objects can belong to the same application as the message sender, but typically are in a remote application. Within the same application, it takes fewer steps to post a message directly to a BLooper than to construct a BMessenger and ask it to send the message--however, the result is the same and both methods are equally efficient.

BMessenger objects can be transported across application boundaries. You can create one for a particular BHandler/BLooper combination in your application and pass it by value to a remote application. That application can then use the BMessenger to target the objects in your application. This is, in fact, the only way for an application to get a BMessenger that can target a remote object (other than a remote BApplication object).

## Constructor and Destructor

### BMessenger()

          BMessenger(const char *signature,
             team_id team = -1,
             status_t *error = NULL)
          BMessenger(const BHandler *handler,
             const BLooper *looper = NULL,
             status_t *error = NULL)
          BMessenger(const BMessenger &messenger)
          BMessenger(void)

Initializes the BMessenger so that it can send messages to an application identified by its signature or by its team. The application must be running when the BMessenger is constructed.

If the signature passed is `NULL`, the application is identified by its team only. If the team specified is -1, as it is by default, the application is identified by its signature only. If both a real signature and a valid team identifier are passed, they must match--the signature must identify the team application. If more than one instance of the signature application happens to be running, the team picks out a particular instance as the BMessenger's target. Without a valid team argument, the constructor arbitrarily picks one of the instances.

BMessengers constructed in this way send messages to the main thread of the remote application, where they're received and handled by that application's BApplication object. This type of messenger is needed to initiate communication with another application.

A BMessenger can also be aimed at a particular BHandler object--or at the preferred handler for a particular BLooper. For this type of BMessenger, you must pass the constructor a pointer to a BHandler or BLooper living in your application:

- If a target handler is specified, the BMessenger will send messages to the BLooper associated with that BHandler object, and the BLooper will dispatch them to the BHandler. The target BHandler must be able to tell the BMessenger (through its `Looper()` function) which BLooper object it's associated with. The BMessenger asks for this information at the time of construction. Therefore, the handler must either be a BLooper itself or have been added to a BLooper's list of eligible handlers.

  Because the handler identifies its BLooper, there's no need to separately specify the BLooper to the constructor. The looper argument can be left `NULL`, as it is by default. If a specific looper is named, it must match the object that `Looper()` returns for the handler.

- A target looper must be specified only if the handler is `NULL`. In this case, the BMessenger will send messages to the BLooper and the BLooper will dispatch them to whatever object happens to be its preferred handler at the time. This permits the targeting decision to be made dynamically.

- The target handler and looper cannot both be `NULL`, for obvious reasons.

A primary purpose for constructing BMessengers for local BHandlers and BLoopers is to give remote applications access to those objects. You can add a BMessenger to a message and send the message to the remote application. That application can then use the BMessenger to target a BHandler and BLooper in your application.

The constructor reports its success or failure by placing an error code in the `status_t` variable that the error argument points to, provided that the argument isn't omitted or `NULL`. If it can't make a connection to the signature application--possibly because no such application is running--it reports a `B_BAD_VALUE` error. If passed an invalid team identifier, it registers a `B_BAD_TEAM_ID` error. If the team and the signature don't match, it conveys a `B_MISMATCHED_VALUES` error.

If it can't discover a BLooper from the target BHandler, the constructor reports a `B_BAD_HANDLER` error. If a looper is specified but the BHandler is associated with another BLooper object, it registers a `B_MISMATCHED_VALUES` error. If neither a handler nor a looper is specified, it reports a `B_BAD_VALUE` error.

If all goes well, the constructor puts `B_OK` in the error variable. It's a good idea to check for an error before asking the new BMessenger to send a message.

A BMessenger can also be constructed as a copy of another BMessenger,

       BMessenger newOne(anotherMessenger);

or be assigned from another object:

       BMessenger newOne = anotherMessenger;

If the construction of a BMessenger fails for any reason, the `IsValid()` function will report that the resulting object is not to be trusted:

       BMessenger messenger(localHandler);
       if ( messenger.IsValid() ) {
           . . .
       }

A BMessenger constructed without arguments is invalid until it's initialized with another BMessenger.

A BMessenger object can send messages to only one destination. Once constructed, you can cache it and reuse it repeatedly to communicate with that destination. It should be freed after it's no longer needed (or it becomes invalid). The BRoster object can provide signature and team information about possible destinations.

See also: the BInvoker, BRoster, and BMessage classes, `Target()`, `IsValid()`

### ~BMessenger()

          ~BMessenger()

Frees all memory allocated by the BMessenger, if any was allocated at all.

## Member Functions

### IsTargetLocal() see Target()

### IsValid()

          bool IsValid(void) const

Returns `true` if the BMessenger is connected to a destination BLooper, and `false` if not. A BMessenger might become disconnected from its target if, for example, the user quit the destination application or that application destroyed the target BLooper.

This function doesn't check whether the target BHandler is valid; it reports only on the status of the target BLooper.

### LockTarget(), LockTargetWithTimeout()

          bool LockTarget(void) const

          status_t LockTargetWithTimeout(bigtime_t timeout) const

These functions lock the BLooper that the BMessenger targets, but only if the target is local (only if the BLooper is in the same team as the BMessenger). They work exactly like the counterpart BLooper `Lock()` and `LockWithTimeout()` functions, and they return what those functions return, with this additional stipulation: If the target BLooper isn't local, `LockTarget()` returns `false` and `LockTargetWithTimeout()` returns `B_BAD_VALUE`.

Each successful lock must be balanced by a call to unlock the BLooper using the BLooper's `Unlock()` function. For example:

       if ( myMessenger.LockTarget() ) {
           BLooper *myLooper;
           BHandler *myHandler = myMessenger.Target(&myLooper);
           . . .
           myLooper->Unlock();
       }

The BMessenger functions have only one advantage over their BLooper counterparts. If you keep a pointer to a BLooper object and call `Lock()` through the pointer,

       if ( myLooper->Lock() ) {
           . . .
           myLooper->Unlock();
       }

it may return `true` even though it's not locking the object you think it is. This strange result can happen if the BLooper is deleted and another object, perhaps another BLooper, is allocated in the same memory space. The pointer won't register the difference. However, the BMessenger is not fooled. If it's target goes away, `LockTarget()` will return `false` and `LockTargetWithTimeout()` will return `B_BAD_VALUE`.

See also: `BLooper::Lock()`

### SendMessage()

          status_t SendMessage(BMessage *message,
             BMessage *reply,
             bigtime_t sendTimeout = B_INFINITE_TIMEOUT,
             bigtime_t replyTimeout = B_INFINITE_TIMEOUT) const
          status_t SendMessage(BMessage *message,
             BHandler *replyHandler = NULL,
             bigtime_t sendTimeout = B_INFINITE_TIMEOUT) const
          status_t SendMessage(uint32 command, BMessage *reply) const
          status_t SendMessage(uint32 command, BHandler *replyHandler = NULL) const

Sends a message to the destination that was designated when the BMessenger was constructed. The caller retains responsibility for the message passed to this function; the destination thread will receive a copy.

You can ask for a synchronous reply to the message you send or designate a BHandler for an asynchronous reply:

- Supplying a reply argument requests a message back from the destination. Before returning, `SendMessage()` waits for an answer and fills in the reply BMessage with the information it receives. The caller is responsible for allocating and deleting the reply message. Typically, the reply BMessage is an empty container for the reply allocated on the stack:

          BMessage message(STAY_THE_COURSE);
          BMessage reply;
          myMessenger.SendMessage(&message, &reply);

       If the destination doesn't send a reply before the message is deleted, the system sends one with B_NO_REPLY as the what data member.  Check the reply message before proceeding.  If there's an error in receiving the reply message, SendMessage() will return an error, such as B_BAD_PORT_ID, indicating that something went wrong,.

- If a reply isn't requested, `SendMessage()` returns immediately; any reply to the message will be received asynchronously. If a replyHandler is specified, the reply will be directed to that BHandler object. If a handler isn't specified, it will be directed to the BApplication object.

  The replyHandler is subject to the same restriction as a target BHandler passed to the BMessenger constructor: It must be associated with a BLooper object (or be a BLooper itself) .

By default, `SendMessage()` doesn't return until it delivers the message. If it can't do so immediately (for example, if the destination BLooper's port queue is full), it blocks until it can accomplish its mission.

However, you can limit how long it will block by setting a timeout in microseconds. The sendTimeout argument is the number of microseconds you give the function to place the message in the destination BLooper's port. If `SendMessage()` is unable to deliver the message in the specified amount of time, it fails and returns an error (`B_TIMED_OUT`). Separate sendTimeout and replyTimeout limits can be set for sending the message and for receiving a synchronous reply. There is no time limit if a timeout value is set `B_INFINITE_TIMEOUT`--as it is by default.

If a command is passed instead of a full message, `SendMessage()` constructs a BMessage object with command as its `what` data member and sends it just like any other message. This is simply a convenience for sending messages that contain no data. The following line of code

       myMessenger->SendMessage(NEVERMORE);

is roughly equivalent to:

       BMessage message(NEVERMORE);
       myMessenger->SendMessage(&message);

You cannot set timeouts for the command versions of this function. They block without a time limit (`B_INFINITE_TIMEOUT`).

If all goes well, `SendMessage()` returns `B_OK`. If not, it returns an error code, typically `B_BAD_PORT_ID` or `B_TIMED_OUT`.

(It's an error for a thread to send a message to itself and expect a synchronous reply. The thread can't respond to the message and wait for a reply at the same time.)

See also: `BMessage::SendReply()`

### Target(), IsTargetLocal()

          BHandler *Target(BLooper **looper) const

          bool IsTargetLocal(void) const

`Target()` returns a pointer to the BHandler object that's targeted to respond to the messages that the BMessenger sends. It also places a pointer to the BLooper that receives its messages in the variable that looper refers to. If the BMessenger is targeted to the BLooper's preferred handler, `Target()` returns `NULL` but identifies the looper.

`Target()` can't provide valid pointers to objects that live in other applications. Therefore, for remote targets, it returns `NULL` and sets the looper pointer to `NULL`. These values could also indicate that the BMessenger hadn't been initialized. `IsTargetLocal()` can distinguish between these case. It returns `true` if the BMessenger is in the same application as its target, and `false` if its target is remote or nonexistent.

### Team()

          inline team_id Team(void) const

Returns the identifier for the team that receives the messages the BMessenger sends.

## Operators

### = (assignment)

          BMessenger &operator =(const BMessenger&)

Assigns one BMessenger to another. After the assignment the two objects are identical and independent copies of each other, with no shared data.

### == (equality)

          bool operator ==(const BMessenger&) const

Returns `true` if the two BMessengers have the same targets for the messages they send, and `false` if not.

The Be Book, in lovely HTML, for BeOS Release 3.

Copyright © 1998 Be, Inc. All rights reserved.

Last modified March 26, 1998.