# The Application Kit: BMessage

Derived from: none

Declared in: be/app/Message.h

Library: libbe.so

## Overview

A BMessage bundles information so that it can be conveyed from one application to another, one thread of execution to another, or even one object to another. Servers use BMessage objects to notify applications about events. An application can use them to communicate with other applications or to initiate activity in a different thread of the same application. In the Interface Kit, BMessages package information that the user can drag from one location on-screen and drop on another. Behind the scenes in the Storage Kit, they convey queries and hand back requested information.

A BMessage is simply a container. The class defines functions that let you put information into a message, determine what kinds of information are present in a message that's been delivered to you, and get the information out. It also has a function that lets you reply to a message once it's received. But it doesn't have functions that can make the initial delivery. For that it depends on the help of other classes in the Application Kit, particularly BLooper and BMessenger. See the "Messaging" section near the beginning of this chapter for an overview of the messaging mechanism and how BMessage objects work with these other classes.

As a data container, a BMessage can be used for purposes other than sending a message. The operating system assigns them at least three other roles:

- They contain the data that's copied to the clipboard.
- They serve as object archives.
- They record document-specific settings for a print job.

The clipboard is represented by the BClipboard class, documented in this chapter. Archiving and the BArchivable class are described in the Support Kit. Print settings are outlined for the BPrintJob class, in the Interface Kit.

The BMessage class defines five sets of functions:

- The primary set deals with the contents of the message. `AddData()` puts data in a message, `ReplaceData()` replaces it with something else, `MakeEmpty()` and `RemoveName()` remove data previously added, `GetInfo()` gets information about the data the message contains, and `FindData()` retrieves it.

  Most of these functions have specialized versions that are optimized to handle a particular type of data--for example, `AddRect()` adds a BRect object, `AddRef()` adds an `entry_ref` structure complete with the string the structure refers to, and `AddMessage()` adds one BMessage to another.

- A smaller set of functions reports on the status of a received message. For example, `IsSourceWaiting()` tells whether the message sender is waiting for a reply, `WasDropped()` says whether it was dragged and dropped, and `DropPoint()` says where it was dropped.

- A few functions, such as `AddSpecifier()` and `PopSpecifier()`, help with the scripting system.

- `SendReply()` can send a reply to a received message. It works just like `SendMessage()` in the BMessenger class, except that it can't initiate the first message in an exchange and it marks the reply message as a reply.

- Finally, `Flatten()` writes the contents of a message as a flat stream of bytes so the message can be stored on disk or manipulated simply as raw data rather than as an object. `Unflatten()` reconstructs the BMessage from its flattened state.

When data is added to a BMessage, it's associated with a name, a number of bytes, and a type code. The name can be anything you choose, and the number of bytes must be accurate. The type code should permit the message receiver to identify the type of data in the message, so it must be defined as part of a protocol that the sender and receiver both understand. A number of codes for common types are defined in the Support Kit; see "Type Codes" in The Support Kit chapter.

## Data Members

uint32 `what`
A coded constant that captures what the message is about. For example, a message that's delivered to report a mouse-down event will have `B_MOUSE_DOWN` as its `what` data member. An application that requests information from another application might put a `TRANSMIT_DATA` or `SEND_INFO` command in the `what` field. A message that's posted as the result of the user clicking a Cancel button might simply have `CANCEL` as the `what` data member and include no other information.

## Constructor and Destructor

### BMessage()

          BMessage(uint32 command)
          BMessage(BMessage *message)
          BMessage(const BMessage &message)
          BMessage(void)

Assigns command as the new BMessage object's `what` data member, and ensures that the object otherwise starts out empty. Given the definition of a message constant such as,

       #define RECEIPT_ACKNOWLEDGED  0x80

a complete message can be created as simply as this:

       BMessage msg(RECEIPT_ACKNOWLEDGED);

As a public data member, `what` can also be set explicitly. The following two lines of code are equivalent to the one above:

       BMessage msg;
       msg.what = RECEIPT_ACKNOWLEDGED;

Other information can be added to the message by calling `AddData()` or a kindred function.

A BMessage can also be constructed as a copy of another message, or assigned from another message:

       BMessage *differentMsg = new BMessage(QUIT_THAT);
       msg = *differentMsg;

It's necessary to copy any messages you receive that you want to keep, since the thread that receives the message automatically deletes it before getting the next message. (More typically, you'd copy any data you want to save from the message, but not the BMessage itself.)

As an alternative to copying a received message, you can sometimes detach it from the message loop so that it won't be deleted (see `DetachCurrentMessage()` in the BLooper class).

BMessage objects can be either dynamically allocated with the `new` operator or statically allocated, as shown in the examples above.

When posting or sending a message, or when initiating a drag-and-drop operation, you retain ownership of the BMessage and are responsible for being sure it's destroyed. Stack allocation is therefore often adequate. However, when assigning a BMessage to another object (such as a BInvoker), ownership is transferred with it. Since the object must continue to live after the assigning function returns, dynamic allocation is usually required.

See also: `BLooper::DetachCurrentMessage()`

### ~BMessage()

          virtual ~BMessage()

Frees all memory allocated to hold message data. If the message sender is expecting a reply but hasn't received one, a default reply (with `B_NO_REPLY` as the `what` data member) is sent before the message is destroyed.

The system retains ownership of the messages it delivers to you. Each message loop routinely deletes delivered BMessages after the application is finished responding to them.

## Member Functions

### AddData(), AddBool(), AddInt8(), AddInt16(), AddInt32(), AddInt64(), AddFloat(), AddDouble(), AddString(), AddPoint(), AddRect(), AddRef(), AddMessage(), AddMessenger(), AddPointer(), AddFlat()

          status_t AddData(const char *name, type_code type,
             const void *data,
             ssize_t numBytes,
             bool fixedSize = true,
             int32 numItems = 1)

          status_t AddBool(const char *name, bool aBool)

          status_t AddInt8(const char *name, int8 anInt8)

          status_t AddInt16(const char *name, int16 anInt16)

          status_t AddInt32(const char *name, int32 anInt32)

          status_t AddInt64(const char *name, int64 anInt64)

          status_t AddFloat(const char *name, float aFloat)

          status_t AddDouble(const char *name, double aDouble)

          status_t AddString(const char *name, const char *string)

          status_t AddPoint(const char *name, BPoint point)

          status_t AddRect(const char *name, BRect rect)

          status_t AddRef(const char *name, const entry_ref *ref)

          status_t AddMessage(const char *name, const BMessage *message)

          status_t AddMessenger(const char *name, BMessenger messenger)

          status_t AddPointer(const char *name, const void *pointer)

          status_t AddFlat(const char *name, BFlattenable *object, int32 numItems = 1)

These functions put data in the BMessage. `AddData()` copies numBytes of data into the object, and assigns the data a name and a type code. It copies whatever the data pointer points to. For example, if you want to add a string of characters to the message, data should be the string pointer (`char *`). If you want to add only the string pointer, not the characters themselves, data should be a pointer to the pointer (`char **`). The assigned type must be a specific data type; it should not be `B_ANY_TYPE`.

Most of the other functions--`AddBool()`, `AddFloat()`, `AddRect()`, and so on--are specialized and simplified variants of `AddData()`. They each add a particular type of data to the message, ensure its integrity, and register it under the appropriate type code, as tabulated below:

Function | Adds type | Assigns type code
`AddBool()` | a `bool` | `B_BOOL_TYPE`
`AddInt8()` | an `int8` or `uint8` | `B_INT8_TYPE`
`AddInt16()` | an `int16` or `uint16` | `B_INT16_TYPE`
`AddInt32()` | an `int32` or `uint32` | `B_INT32_TYPE`
`AddInt64()` | an `int64` or `uint64` | `B_INT64_TYPE`
`AddFloat()` | a `float` | `B_FLOAT_TYPE`
`AddDouble()` | a `double` | `B_DOUBLE_TYPE`
`AddString()` | a character string | `B_STRING_TYPE`
`AddPoint()` | a BPoint object | `B_POINT_TYPE`
`AddRect()` | a BRect object | `B_RECT_TYPE`
`AddRef()` | an `entry_ref` | `B_REF_TYPE`
`AddMessage()` | a BMessage object | `B_MESSAGE_TYPE`
`AddMessenger()` | a BMessenger object | `B_MESSENGER_TYPE`
`AddPointer()` | a pointer to anything | `B_POINTER_TYPE`

Each of these type-specific functions calculates the number of bytes in the data they add. `AddString()`, like `AddData()`, takes a pointer to the data it adds. The string must be null-terminated; the null character is counted and copied into the message. Similarly, `AddRef()` adds the pointed to `entry_ref` structure to the message (and the variable-length name that's one of the elements of the structure); `AddMessage()` adds one BMessage to another.

The other functions are simply passed the data directly. For example, `AddInt32()` takes an `int32` or `uint32` and `AddMessenger()` takes a BMessenger object, whereas `AddData()` would be passed a pointer to an `int32` and a pointer to a BMessenger. `AddPointer()` adds only the pointer it's passed, not the data it points to. To accomplish the same thing, `AddData()` would take a pointer to the pointer. (The pointer will be valid only locally; it won't be useful to a remote destination.)

`AddFlat()` flattens an object (by calling its `Flatten()` function) and adds the flat data to the message. It calls the object's `TypeCode()` function to learn the type code it should associate with the data. `FindFlat()` will reverse this process and restore the object to its unflat form. The BFlattenable protocol is documented in the Support Kit.

Names of data can be arbitrarily assigned, but a name can't be more than 255 characters long.

If more than one item of data is added under the same name, the BMessage creates an array of data for that name. Each successive call appends another data element to the end of the array. For example, the following code creates an array named "primes" with 37 stored at index 0, 223 stored at index 1, and 1,049 stored at index 2.

       BMessage *msg = new BMessage(NUMBERS);
       int32 x = 37;
       int32 y = 223;
       int32 z = 1049;

       msg->AddInt32("primes", x);
       msg->AddFloat("pi", 3.1416);
       msg->AddInt32("primes", y);
       msg->AddData("primes", B_INT32_TYPE, &z, sizeof(int32));

Note that entering other data between some of the elements of an array--in this case, "pi"--doesn't increment the array index.

All elements in a named array must be of the same type; it's an error to try to mix types under the same name.

When you call `AddData()` to place the first item in an array under a new name, you can provide it with two arguments, fixedSize and numItems, that will improve the object's efficiency when it adds subsequent items to the array. If the fixedSize flag is `true`, each item in the array must have the same number of bytes; if the flag is `false`, items can vary in size. For example, all items in an array of integers will be the same size, but the items in an array of strings are likely to have differing lengths. `AddData()` takes the numItems argument as a hint, an indication of how many items will be added to the array. It can more economically allocate memory for the items if it can anticipate how many there will be.

When adding subsequent items to the array, `AddData()` ignores the fixedSize and numItems arguments; they're relevant only when the array is first established. You can call `AddData()` with these arguments to provide the necessary hints when setting up the array, then call other functions to add more items.

You can also provide a numItems hint to `AddFlat()` when you call it to set up a new array. `AddFlat()` calls the object's `IsFixedSize()` function to discover whether all items in the array will be the same size.

These functions return `B_ERROR` if the data is too massive to be added to the message, `B_BAD_TYPE` if the data can't be added to an existing array because it's the wrong type, `B_NO_MEMORY` if the BMessage can't get enough memory to hold the data, and `B_BAD_VALUE` if the proposed name for the data is longer than 255 bytes. If all goes well, they return `B_OK`.

There's no limit on the number of named fields a message can contain or on the size of a field's data. However, since the search is linear, combing through a very long list of names to find a particular piece of data may be inefficient. Also, because of the amount of data that must be moved, an extremely large message (over 100,000 bytes, say) can slow the delivery mechanism. It's sometimes better to put some of the information in a common location (a file, a private clipboard, a shared area of memory) and just refer to it in the message. Sometimes later messages can be used to arrange for the transfer of data if the message receiver requires it.

See also: `FindData()`, `GetInfo()`

### AddSpecifier()

          status_t AddSpecifier(const BMessage *message)
          status_t AddSpecifier(const char *property)
          status_t AddSpecifier(const char *property, int32 index)
          status_t AddSpecifier(const char *property, int32 index, int32 range)
          status_t AddSpecifier(const char *property, const char *name)

Adds a specifier to the specifier stack. There are several variations of this method. The first adds the specifier message to the specifier stack. The other methods add a specifier targeting the property property, with specifier constants `B_DIRECT_SPECIFIER`, `B_INDEX_SPECIFIER`, `B_RANGE_SPECIFIER`, and `B_NAME_SPECIFIER`, respectively. For all other specifiers, you must construct the specifier separately and then call `AddSpecifier()` on the message. For more information about specifiers, see the "Scripting" section near the beginning of this chapter.

Specifiers are stored in a data array named "specifiers." However, since `AddSpecifier()` also sets the notion of the current specifier, specifiers should always be added to a scripting message with this method rather than with `AddMessage()`.

`AddSpecifier()` returns `B_OK` if it's able to add the specifier to the BMessage and an error code, generally only `B_NO_MEMORY` to indicate that it has run out of memory, if not.

See also: `GetCurrentSpecifier()`, `HasSpecifiers()`, `PopSpecifier()`

### CountNames()

          int32 CountNames(type_code type) const

Returns the number of named data fields in the BMessage that store data of the specified type. An array of information held under a single name counts as one field; each name is counted only once, no matter how many data items are stored under that name.

If type is `B_ANY_TYPE`, this function counts all named fields. If type is a specific type, it counts only fields that store data registered as that type.

See also: `GetInfo()`

### DropPoint() see WasDropped()

### FindData(), FindBool(), FintInt8(), FindInt16(), FindInt32(), FindInt64(), FindFloat(), FindDouble(), FindString(), FindPoint(), FindRect(), FindRef(), FindMessage(), FindMessenger(), FindPointer(), FindFlat()

          status_t FindData(const char *name,
             type_code type,
             int32 index,
             const void **data,
             ssize_t *numBytes) const
          status_t FindData(const char *name,
             type_code type,
             const void **data,
             ssize_t *numBytes) const

          status_t FindBool(const char *name,
             int32 index,
             bool *aBool) const
          status_t FindBool(const char *name, bool *aBool) const
          bool FindBool(const char *name, int32 index = 0) const

          status_t FindInt8(const char *name,
             int32 index,
             int8 *anInt8) const
          status_t FindInt8(const char *name,
             int8 *anInt8) const

          status_t FindInt16(const char *name,
             int32 index,
             int16 *anInt16) const
          status_t FindInt16(const char *name, int16 *anInt16) const
          int16 FindInt16(const char *name, int32 index = 0) const

          status_t FindInt32(const char *name,
             int32 index,
             int32 *anInt32) const
          status_t FindInt32(const char *name, int32 *anInt32) const
          int32 FindInt32(const char *name, int32 index = 0) const

          status_t FindInt64(const char *name,
             int32 index,
             int64 *anInt64) const
          status_t FindInt64(const char *name, int64 *anInt64) const

          status_t FindFloat(const char *name,
             int32 index,
             float *aFloat) const
          status_t FindFloat(const char *name, float *aFloat) const
          float FindFloat(const char *name, int32 index = 0) const

          status_t FindDouble(const char *name,
             int32 index,
             double *aDouble) const
          status_t FindDouble(const char *name, double *aDouble) const
          double FindDouble(const char *name, int32 index = 0) const

          status_t FindString(const char *name,
             int32 index,
             const char **string) const
          status_t FindString(const char *name, const char **string) const
          const char *FindString(const char *name, int32 index = 0) const

          status_t FindPoint(const char *name,
             int32 index,
             BPoint *point) const
          status_t FindPoint(const char *name, BPoint *point) const
          BPoint FindPoint(const char *name, int32 index = 0) const

          int32 FindRect(const char *name,
             int32 index,
             BRect *rect) const
          int32 FindRect(const char *name, BRect *rect) const
          BRect FindRect(const char *name, int32 index = 0) const

          status_t FindRef(const char *name,
             int32 index,
             entry_ref *ref) const
          status_t FindRef(const char *name, entry_ref *ref) const

          status_t FindMessage(const char *name,
             int32 index,
             BMessage *message) const
          status_t FindMessage(const char *name, BMessage *message) const

          status_t FindMessenger(const char *name,
             int32 index,
             BMessenger *messenger) const
          status_t FindMessenger(const char *name, BMessenger *messenger) const

          status_t FindPointer(const char *name,
             int32 index,
             void **pointer) const
          status_t FindPointer(const char *name, void **pointer) const

          status_t FindFlat(const char *name,
             int32 index,
             BFlattenable *object) const
          status_t FindFlat(const char *name, BFlattenable *object) const

These functions retrieve data from the BMessage. Each looks for data stored under the specified name. If more than one data item has the same name, an index can be provided to tell the function which item in the name array it should find. Indices begin at 0. If an index isn't provided, the function will find the first, or only, item in the array.

`FindData()` places a pointer to the requested data item in the variable referred to by data and records the size of the item (the number of bytes it takes up) in the variable referred to by numBytes. It asks for data of a specified type. If the type is `B_ANY_TYPE`, it provides a pointer to the data no matter what type it actually is. But if type is a specific data type, it provides the pointer only if the name field holds data of that particular type.

It's important to keep in mind that `FindData()` only gives you a pointer to the data, never the data itself. If the data is a pointer--for example, a pointer to an object--it provides a pointer to the pointer. The variable that's assigned the returned pointer must be doubly indirect. For example:

       MyClass **object;
       ssize_t numBytes;
       if ( !msg->FindData("name", B_POINTER_TYPE, &object, &numBytes) )
           (*object)->GetSomeInformation();
           . . .
       }

The other functions are specialized versions of `FindData()`. They match the corresponding `Add`...`()` functions and search for named data of a particular type, as described below:

Function | Finds data | Registered as type
`FindBool()` | a `bool` | `B_BOOL_TYPE`
`FindInt8()` | an `int8` or `uint8` | `B_INT8_TYPE`
`FindInt16()` | an `int16` or `uint16` | `B_INT16_TYPE`
`FindInt32()` | an `int32` or `uint32` | `B_INT32_TYPE`
`FindInt64()` | an `int64` or `uint64` | `B_INT64_TYPE`
`FindFloat()` | a `float` | `B_FLOAT_TYPE`
`FindDouble)` | a `double` | `B_DOUBLE_TYPE`
`FindString()` | a character string | `B_STRING_TYPE`
`FindPoint()` | a BPoint object | `B_POINT_TYPE`
`FindRect()` | a BRect object | `B_RECT_TYPE`
`FindRef()` | an `entry_ref` | `B_REF_TYPE`
`FindMessage()` | a BMessage object | `B_MESSAGE_TYPE`
`FindMessenger()` | a BMessenger object | `B_MESSENGER_TYPE`
`FindPointer()` | a pointer to anything | `B_POINTER_TYPE`

`FindString()` works like `FindData()`; it places a pointer to the string in the variable that its string argument refers to. You have to copy the characters yourself.

The other type-specific functions retrieve the requested data item from the message by copying it to the variable referred to by the last argument; you get the data, not just a pointer to it. For example, `FindMessenger()` assigns the BMessenger it finds in the message to the messenger object, whereas `FindData()` would provide only a pointer to a BMessenger. `FindPointer()` puts the found pointer in the `void*` variable that pointer refers to; `FindData()`, as illustrated above, would provide a pointer to the pointer. (If the message was delivered from a remote source, pointers retrieved from the message won't be valid.)

`FindRef()` retrieves an `entry_ref` structure; the data that's used to reconstitute the structure may have been added as an `entry_ref` (through `AddRef()`), or as a flattened BPath object (`AddFlat()`).

`FindFlat()` assigns the object stored in the BMessage to the object passed as an argument--it calls the object's `Unflatten()` function and passes it the flat data from the message--provided that the two objects have compatible types. The argument object's `AllowsTypeCode()` function must return `true` when tested with the type code stored in the message; if not, `FindFlat()` fails and returns `B_BAD_VALUE`.

If these functions can't find any data associated with name, they return a `B_NAME_NOT_FOUND` error. If they can't find name data of the requested type (or the type the function returns), they return `B_BAD_TYPE`. If the index is out of range, they return `B_BAD_INDEX`. You can rely on the values they retrieve only if they return `B_OK` and the data was correctly recorded when it was added to the message.

When they fail, `FindData()` and `FindString()` provide `NULL` pointers. `FindRect()` hands you an invalid rectangle and `FindMessenger()` an invalid BMessenger. Most of the other functions set the data values to 0, which may be indistinguishable from valid values.

Finding a data item doesn't remove it from the BMessage.

(Several functions, such as `FindRect()` and `FindInt32()`, have versions that return the found value directly. These versions don't report errors and may not be supported in the future.)

See also: `GetInfo()`, `AddData()`

### Flatten(), Unflatten(), FlattenedSize()

          status_t Flatten(BDataIO *object, ssize_t *numBytes = NULL) const
          status_t Flatten(char *address, ssize_t numBytes = NULL) const

          status_t Unflatten(BDataIO *object)
          status_t Unflatten(const char *address)

          ssize_t FlattenedSize(void) const

These functions write the BMessage and the data it contains to a "flat" (untyped) buffer of bytes, and reconstruct a BMessage object from such a buffer.

If passed a BDataIO object (including a BFile), `Flatten()` calls the object's `Write()` function to write the message data. If passed the address of a buffer, it begins writing at the start of the buffer. `FlattenedSize()` returns the number of bytes you must provide in the buffer to hold the flattened object. `Flatten()` places the number of bytes actually written in the variable that its numBytes argument refers to.

`Unflatten()` empties the BMessage of any information it may happen to contain, then initializes the object from data read from the buffer. If passed a BDataIO object, it calls the object's `Read()` function to read the message data. If passed a buffer address, it begins reading at the start of the buffer. It's up to the caller to make sure that `Unflatten()` reads data that `Flatten()` wrote and that pointers are positioned correctly.

`Flatten()` returns any errors encountered when writing the data, or `B_OK` if there is no error.

If it doesn't recognize the data in the buffer as being a flattened object or there's a failure in reading the data, `Unflatten()` returns `B_BAD_VALUE`. If it doesn't have adequate memory to recreate the whole message, it returns `B_NO_MEMORY`. Otherwise, it returns `B_OK`.

See also: the BDataIO class in the Support Kit

### GetCurrentSpecifier(), PopSpecifier()

          status_t GetCurrentSpecifier(int32 *index,
             BMessage *specifier = NULL,
             int32 *what = NULL,
             const char **property = NULL) const

          status_t PopSpecifier(void)

`GetCurrentSpecifier()` unpacks the current specifier in the BMessage, the one at the top of the specifier stack; `PopSpecifier()` changes the notion of which specifier is current, by popping the current one from the stack.

These functions aid in implementing a class-specific version of BHandler's `ResolveSpecifier()` function--the first gets the specifier that needs to be resolved, and the second pops it from the stack after it is resolved. You can also call them to examine relevant specifiers when handling a message that targets an object property (such as `B_GET_PROPERTY`).

A scripting BMessage keeps specifiers in a data array named "specifiers"; each specifier is itself a BMessage, but one with a special structure and purpose in the scripting system. See the "Scripting" section near the beginning of this chapter for an overview of the system and the place of specifiers in it.

The specifiers in a message are ordered and, until `PopSpecifier()` is called, the one that was added last--the one with the greatest index--is the current specifier. `PopSpecifier()` merely decrements the index that picks the current specifier; it doesn't delete anything from the BMessage.

`GetCurrentSpecifier()` puts the index of the current specifier in the variable that its first argument, index, refers to. If other arguments are provided, it makes the specifier BMessage a copy of the current specifier. It also extracts two pieces of information from the specifier: It places the `what` data member of the specifier in the what variable and a pointer to the property name in the property variable. These last two output arguments won't be valid if the specifier argument is `NULL`.

Both functions fail if the BMessage doesn't contain specifiers. In addition, `GetCurrentSpecifier()` fails if it can't find data in the BMessage for its specifier and property arguments, and `PopSpecifier()` fails if the BMessage isn't one that has been delivered to you after being processed through a message loop. When it fails, `GetCurrentSpecifier()` returns `B_BAD_SCRIPT_SYNTAX`, but `PopSpecifier()` returns `B_BAD_VALUE`. On success, both functions return `B_OK`.

See also: `AddSpecifier()`, `HasSpecifiers()`, `BHandler::ResolveSpecifier()`

### GetInfo()

          status_t GetInfo(const char *name,
             type_code *typeFound,
             int32 *countFound = NULL) const
          status_t GetInfo(type_code type, int32 index,
             char **nameFound,
             type_code *typeFound,
             int32 *countFound = NULL) const

Provides information about the data fields stored in the BMessage.

When passed a name that matches a name within the BMessage, `GetInfo()` places the type code for data stored under that name in the variable referred to by typeFound and writes the number of data items with that name into the variable referred to by countFound. It then returns `B_OK`. If it can't find a name field within the BMessage, it sets the countFound variable to 0, and returns `B_NAME_NOT_FOUND` (without modifying the typeFound variable).

When passed a type and an index, `GetInfo()` looks only at fields that store data of the requested type and provides information about the field at the requested index. Indices begin at 0 and are type specific. For example, if the requested type is `B_DOUBLE_TYPE` and the BMessage contains a total of three named fields that store `double` data, the first field would be at index 0, the second at 1, and the third at 2--no matter what other types of data actually separate them in the BMessage, and no matter how many data items each field contains. (Note that the index in this case ranges over fields, each with a different name, not over the data items within a particular named field.) If the requested type is `B_ANY_TYPE`, this function looks at all fields and gets information about the one at index whatever its type.

If successful in finding data of the type requested at index, `GetInfo()` returns `B_OK` and provides information about the data through the last three arguments:

- It places a pointer to the name of the data field in the variable referred to by nameFound.

- It puts the code for the type of data the field contains in the variable referred to by typeFound. This will be the same as the type requested, unless the requested type is `B_ANY_TYPE`, in which case typeFound will be the actual type stored under the name.

- It records the number of data items stored within the field in the variable referred to by countFound.

If `GetInfo()` can't find data of the requested type at index, it sets the countFound variable to 0, and returns `B_BAD_TYPE`. If the index is out of range, it returns `B_BAD_INDEX`.

This version of `GetInfo()` can be used to iterate through all the BMessage's data. For example:

       char  *name;
       uint32  type;
       int32   count;

       for ( int32 i = 0;
             msg->GetInfo(B_ANY_TYPE, i, &name, &type, &count);
             i++ ) {
           . . .
       }

If the index is incremented from 0 in this way, all data of the requested type will have been read when `GetInfo()` returns `false`. If the requested type is `B_ANY_TYPE`, as shown above, it will reveal the name and type of every field in the BMessage.

See also: `HasData()`, `AddData()`, `FindData()`

### HasData(), HasBool(), HasInt8(), HasInt16(), HasInt32(), HasInt64(), HasFloat(), HasDouble(), HasString(), HasPoint(), HasRect(), HasRef(), HasMessage(), HasMessenger(), HasPointer()

          bool HasData(const char *name, type_code type, int32 index = 0) const

          bool HasBool(const char *name, int32 index = 0) const

          bool HasInt8(const char *name, int32 index = 0) const

          bool HasInt16(const char *name, int32 index = 0) const

          bool HasInt32(const char *name, int32 index = 0) const

          bool HasInt64(const char *name, int32 index = 0) const

          bool HasFloat(const char *name, int32 index = 0) const

          bool HasDouble(const char *name, int32 index = 0) const

          bool HasString(const char *name, int32 index = 0) const

          bool HasPoint(const char *name, int32 index = 0) const

          bool HasRect(const char *name, int32 index = 0) const

          bool HasRef(const char *name, int32 index = 0) const

          bool HasMessage(const char *name, int32 index = 0) const

          bool HasMessenger(const char *name, int32 index = 0) const

          bool HasPointer(const char *name, int32 index = 0) const

These functions test whether the BMessage contains data of a given name and type. They're generally less useful than the corresponding `Find`...`()` functions. If the message contains the data you're looking for, you probably will want to call `Find`...`()` to get it. Since the `Find`...`()` functions return errors if the message doesn't have data of the requested name and type, it's more efficient to just call `Find`...`()` and not bother with `Has`...`()`. At any rate, here's how these functions work:

If type is `B_ANY_TYPE` and no index is provided, `HasData()` returns `true` if the BMessage stores any data at all under the specified name, regardless of its type, and `false` if the name passed doesn't match any within the object.

If type is a particular type code, `HasData()` returns `true` only if the BMessage has a name field that stores data of that type. If the type and name don't match, it returns `false`.

If an index is supplied, `HasData()` returns `true` only if the BMessage has a name field that stores a data item of the specified type at that particular index. If the index is out of range, it returns `false`.

The other functions--`HasBool()`, `HasFloat()`, `HasPoint()`, and so on--are specialized versions of `HasData()`. They test for a particular type of data stored under the specified name.

See also: `GetInfo()`

### HasSpecifiers()

          bool HasSpecifiers(void) const

Returns `true` if the BMessage has specifiers added by an `AddSpecifier()` function, and `false` if not.

See also: `AddSpecifier()`, `GetCurrentSpecifier()`

### IsEmpty() see MakeEmpty()

### IsReply() see WasDelivered()

### IsSourceRemote() see WasDelivered()

### IsSourceWaiting() see WasDelivered()

### IsSystem()

          bool IsSystem(void) const

Returns `true` if the `what` data member of the BMessage object identifies it as a system-defined message, and `false` if not.

### MakeEmpty(), IsEmpty()

          status_t MakeEmpty(void)

          bool IsEmpty(void) const

`MakeEmpty()` removes and frees all data that has been added to the BMessage, without altering the `what` constant. It returns `B_OK`, unless the message can't be altered (as it can't if it's being dragged), in which case it returns `B_ERROR`.

`IsEmpty()` returns `true` if the BMessage has no data (whether or not it was emptied by `MakeEmpty()`), and `false` if it has some.

See also: `RemoveName()`

### Previous() see WasDelivered()

### PrintToStream()

          void PrintToStream(void) const

Prints information about the BMessage to the standard output stream (`stdout`). Each field of named data is reported in the following format,

       #entry name, type = type, count = count

where name is the name that the data is registered under, type is the constant that indicates what type of data it is, and count is the number of data items in the named array.

### RemoveName(), RemoveData()

          status_t RemoveName(const char *name)

          status_t RemoveData(const char *name, int32 index = 0)

`RemoveName()` removes all data entered in the BMessage under name and the name itself. `RemoveData()` removes the single item of data at index in the name array. If the array has just one data item, it removes the array and name just as `RemoveName()` would.

Both functions free the memory that was allocated to hold the data, and return `B_OK` when successful. However, if there's no data in the BMessage under name, they return a `B_NAME_NOT_FOUND` error. If message data can be read but can't be changed (as it can't for a message that's being dragged), they both return `B_ERROR`. If the index is out of range, `RemoveData()` returns `B_BAD_INDEX` (the index is too high) or `B_BAD_VALUE` (the value passed is a negative number).

See also: `MakeEmpty()`

### ReplaceData(), ReplaceBool(), ReplaceInt8(), ReplaceInt16(), ReplaceInt32(), ReplaceInt64(), ReplaceFloat(), ReplaceDouble(), ReplaceString(), ReplacePoint(), ReplaceRect(), ReplaceRef(), ReplaceMessage(), ReplaceMessenger(), ReplacePointer(), ReplaceFlat()

          status_t ReplaceData(const char *name,
             type_code type,
             const void *data,
             ssize_t numBytes)
          status_t ReplaceData(const char *name,
             type_code type,
              int32 index,
             const void *data,
             ssize_t numBytes)

          status_t ReplaceBool(const char *name, bool aBool)
          status_t ReplaceBool(const char *name,
             int32 index,
             bool aBool)

          status_t ReplaceInt8(const char *name, int8 anInt8)
          status_t ReplaceInt8(const char *name,
             int32 index,
             int8 anInt8)

          status_t ReplaceInt16(const char *name, int16 anInt16)
          status_t ReplaceInt16(const char *name,
             int32 index,
             int16 anInt16)

          status_t ReplaceInt32(const char *name, long anInt32)
          status_t ReplaceInt32(const char *name,
             int32 index,
             int32 anInt32)

          status_t ReplaceInt64(const char *name, int64 anInt64)
          status_t ReplaceInt64(const char *name,
             int32 index,
             int64 anInt64)

          status_t ReplaceFloat(const char *name, float aFloat)
          status_t ReplaceFloat(const char *name,
             int32 index,
             float aFloat)

          status_t ReplaceDouble(const char *name, double aDouble)
          status_t ReplaceDouble(const char *name,
             int32 index,
             double aDouble)

          status_t ReplaceString(const char *name, const char *string)
          status_t ReplaceString(const char *name,
             int32 index,
             const char *string)

          status_t ReplacePoint(const char *name, BPoint point)
          status_t ReplacePoint(const char *name,
             int32 index,
             BPoint point)

          status_t ReplaceRect(const char *name, BRect rect)
          status_t ReplaceRect(const char *name,
             int32 index,
             BRect rect)

          status_t ReplaceRef(const char *name, entry_ref *ref)
          status_t ReplaceRef(const char *name,
             int32 index,
             entry_ref *ref)

          status_t ReplaceMessage(const char *name, BMessage *message)
          status_t ReplaceMessage(const char *name,
             int32 index,
             BMessage *message)

          status_t ReplaceMessenger(const char *name, BMessenger messenger)
          status_t ReplaceMessenger(const char *name,
             int32 index,
             BMessenger messenger)

          status_t ReplacePointer(const char *name, const void *pointer)
          status_t ReplacePointer(const char *name,
             int32 index,
             const void *pointer)

          status_t ReplaceFlat(const char *name, BFlattenable *object)
          status_t ReplaceFlat(const char *name,
             int32 index,
             BFlattenable *object)

These functions replace a data item in the name field with another item passed as an argument. If an index is provided, they replace the item in the name array at that index; if an index isn't mentioned, they replace the first (or only) item stored under name. If an index is provided but it's out of range, the replacement fails.

`ReplaceData()` replaces an item in the name field with numBytes of data, but only if the type code that's specified for the data matches the type of data that's already stored in the field. The type must be specific; it can't be `B_ANY_TYPE`.

`FindFlat()` replaces a flattened object with another object, provided that the type reported by the argument object (by its `TypeCode()` function) matches the type recorded for the item in the message. If not, it returns `B_BAD_VALUE`.

The other functions are simplified versions of `ReplaceData()`. They each handle the specific type of data declared for their last arguments. They succeed if this type matches the type of data already in the name field, and fail if it does not. The new data is added precisely as the counterpart `Add`...`()` function would add it.

If successful, all these functions return `B_OK`. If unsuccessful, they return an error code--`B_ERROR` if the message is read-only (as it is while the message is being dragged), `B_BAD_INDEX` if the index is out of range, `B_NAME_NOT_FOUND` if the name field doesn't exist, or `B_BAD_TYPE` if the field doesn't contain data of the specified type.

See also: `AddData()`

### ReturnAddress()

          BMessenger ReturnAddress(void)

Returns a BMessenger object that can be used to reply to the BMessage. Calling the BMessenger's `SendMessage()` function is equivalent to calling `SendReply()`, except that the return message won't be marked as a reply. If a reply isn't allowed (if the BMessage wasn't delivered), the returned BMessenger will be invalid.

If you want to use the `ReturnAddress()` BMessenger to send a synchronous reply, you must do so before the BMessage is deleted and a default reply is sent.

See also: `SendReply()`, `WasDelivered()`

### SendReply()

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

Sends a reply message back to the sender of the BMessage (in the case of a synchronous reply) or to a target BHandler (in the case of an asynchronous reply). Whether the reply is synchronous or asynchronous depends on how the BMessage that's sending the reply was itself sent:

- The reply is delivered synchronously if the message sender is waiting for one to arrive. The function that sent the BMessage doesn't return until it receives the reply (or a timeout expires). If an expected reply has not been sent by the time the BMessage object is deleted, a default `B_NO_REPLY` message is returned to the sender. If a reply is sent after the sender gave up waiting for it to arrive, the reply message disappears into the bowels of the system.

- The reply is delivered asynchronously if the message sender isn't waiting for a reply. In this case, the sending function designates a target BHandler and BLooper for any replies that might be sent, then returns immediately after putting the BMessage in the pipeline. Posted messages and messages that are dragged and dropped are also eligible for asynchronous replies.

`SendReply()` works only for BMessage objects that have been processed through a message loop and delivered to you. The caller retains ownership of the reply message passed to `SendReply()`; it can be deleted (or left to die on the stack) after the function returns.

`SendReply()` sends a message--a reply message, to be sure, but a message nonetheless. It behaves exactly like the other message-sending function, BMessenger's `SendMessage()`:

- By passing it a reply argument, you can ask for a synchronous reply to the reply message it sends. It won't return until it receives the reply.

- By supplying a replyHandler argument, you can arrange for an expected asynchronous reply. If a specific target isn't specified, the BApplication object will handle the reply if one is sent.

By default, `SendReply()` doesn't return until the reply message is delivered (placed in the BLooper's port queue). It's possible, in some circumstances, for the receiving port queue to be full, in which case `SendReply()` will block until a slot becomes free. However, you can limit how long `SendReply()` will wait to deliver the message before it gives up and returns. The sendTimeout argument is the number of microseconds you give the function to do its work. If the time limit is exceeded, the function fails and returns an error (`B_TIMED_OUT`).

When asking for a synchronous reply, separate sendTimeout and replyTimeout limits can be set for sending the message and receiving the reply. There is no time limit if a timeout value is set to `B_INFINITE_TIMEOUT`--as it is by default. The function won't block at all if the timeout is set to 0.

If a command is passed rather than a message, `SendReply()` constructs the reply BMessage, initializes its `what` data member with the command constant, and sends it just like any other reply. The command versions of this function have infinite timeouts; they block until the message is delivered and, if requested, a synchronous reply is received.

This function returns `B_OK` if the reply is successfully sent. If there's a problem in sending the message, it returns the same sort of error code as BMessenger's `SendMessage()`. It may also report a reply-specific problem. The more informative return values are as follows:

Error code | Is returned when
`B_BAD_REPLY` | Attempting to reply to a message that hasn't been delivered yet.
`B_DUPLICATE_REPLY` | Sending a reply after one has already been sent and delivered.
`B_BAD_THREAD_ID` | Sending a reply to a destination thread that no longer exists.
`B_BAD_PORT_ID` | Sending a reply to a BLooper and port that no longer exist.
`B_TIMED_OUT` | Taking longer than the specified time limit to deliver a reply message or to receive a synchronous reply to the reply.

If you want to delay sending a reply and keep the BMessage object beyond the time it's scheduled to be deleted, you may be able to detach it from the message loop. See `DetachCurrentMessage()` in the BLooper class.

See also: `BMessenger::SendMessage()`, `BLooper::DetachCurrentMessage()`, `Error`, `ReturnAddress()`

### Unflatten() see Flatten()

### WasDelivered(), IsSourceRemote(), IsSourceWaiting(), IsReply(), Previous()

          bool WasDelivered(void) const

          bool IsSourceRemote(void) const

          bool IsSourceWaiting(void) const

          bool IsReply(void) const

          const BMessage *Previous(void) const

These functions can help if you're engaged in an exchange of messages or managing an ongoing communication.

`WasDelivered()` indicates whether it's possible to send a reply to a message. It returns `true` for a BMessage that was posted, sent, or dropped--that is, one that has been processed through a message loop--and `false` for a message that has not yet been delivered by any means.

`IsSourceRemote()` returns `true` if the message had its source in another application, and `false` if the source is local or the message hasn't been delivered yet.

`IsSourceWaiting()` returns `true` if the message source is waiting for a synchronous reply, and `false` if not. The source thread can request and wait for a reply when calling either BMessenger's `SendMessage()` or BMessage's `SendReply()` function.

`IsReply()` returns `true` if the BMessage is a reply to a previous message (if it was sent by the `SendReply()` function), and `false` if not.

`Previous()` returns the previous message--the message to which the current BMessage is a reply. It works only for a BMessage that's received as an asynchronous reply to a previous message. A synchronous reply is received in the context of the previous message, so it's not necessary to call a function to get it. But when an asynchronous reply is received, the context of the original message is lost; this function can provide it. `Previous()` returns `NULL` if the BMessage isn't an asynchronous reply to another message.

See also: `BMessenger::SendMessage()`, `SendReply()`, `ReturnAddress()`

### WasDropped(), DropPoint()

          bool WasDropped(void) const

          BPoint DropPoint(BPoint *offset = NULL) const

`WasDropped()` returns `true` if the user delivered the BMessage by dragging and dropping it, and `false` if the message was posted or sent in application code or if it hasn't yet been delivered at all.

`DropPoint()` reports the point where the cursor was located when the message was dropped (when the user released the mouse button). It directly returns the point in the screen coordinate system and, if an offset argument is provided, returns it by reference in coordinates based on the image or rectangle the user dragged. The offset assumes a coordinate system with (0.0, 0.0) at the left top corner of the dragged rectangle or image.

Since any value can be a valid coordinate, `DropPoint()` produces reliable results only if `WasDropped()` returns `true`.

See also: `BView::DragMessage()`

## Operators

### = (assignment)

          BMessage &operator =(const BMessage&)

Assigns one BMessage object to another. After the assignment, the two objects are duplicates of each other without shared data.

### new

          void *operator new(size_t numBytes)

Allocates memory for a BMessage object, or takes the memory from a previously allocated cache. The caching mechanism is an efficient way of managing memory for objects that are created frequently and used for short periods of time, as BMessages typically are.

### delete

          void operator delete(void *memory, size_t numBytes)

Frees memory allocated by the BMessage version of `new`, which may mean restoring the memory to the cache.

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

Copyright © 1998 Be, Inc. All rights reserved.

Last modified March 26, 1998.