BMessenger

Derived from: none

Declared in: be/app/Messenger.h

Library: libbe.so


Overview

[method summary]

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:

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(BMessage *message,
         BMessenger *replyMessenger, 
         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 or BMessenger for an asynchronous reply:

      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,.

B_NO_REPLY messages are never sent in response to asynchronous messages.

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. You might get B_WOULD_BLOCK returned, if there are already too many messages pending; in this case, you can snooze for a while, then try again. If something goes wrong, 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 4.

Copyright © 1998 Be, Inc. All rights reserved.

Last modified December 9, 1998.