The represent_as Attribute

The represent_as attribute lets you specify how a particular remotable data type is represented for the application. This is done by specifying the name of the represented type for a known transmittable type and supplying the routines to convert the data type to and from the other data type. You must also supply the routines to free the memory used by the data type objects.

You use the represent_as attribute to present an application with a different and perhaps nonremotable data type, instead of the type that is actually transmitted between the client and server. Also, the type the application manipulates can be unknown at the time of MIDL compilation. When you choose a well-defined transmittable type, you need not be concerned about data representation in the heterogenic environment. The represent_as attribute can make your application more efficient by reducing the amount of data transmitted over the network.

The represent_as attribute is similar to the transmit_as attribute. However, while transmit_as lets you specify a data type that will be used for transmission, represent_as lets you specify how a data type is represented for the application. The represented type need not be defined in the MIDL processed files; it can be defined at the time the stubs are compiled with the C compiler. To do this, use the include directive in the ACF to compile the appropriate header file. For example, the following ACF defines a local represented repr_type for the given transmittable named_type:

typedef [represent_as(repr_type) [, type_attribute_list] named_type;
 

The following table describes the four user-supplied routines:

Routine Description
named_type_from_local Allocates an instance of the network type and converts from the local type to the network type.
named_type_to_local Converts from the network type to the local type.
named_type_free_local Frees memory allocated by a call to the named_type_to_local routine, but not the type itself.
named_type_free_inst Frees storage for the network type (both sides).

Other than by these four user-supplied routines, the named type is not manipulated by the application and the only type visible to the application is the represented type. The represented type name is used instead of the named type name in the prototypes and stubs generated by the compiler. You must supply the set of routines for both sides.

For temporary named_type objects, the stub will call named_type_free_inst to free any memory allocated by a call to named_type_from_local.

If the represented type is a pointer or contains a pointer, the named_type_to_local routine must allocate pointees of the pointers (the represented type object itself is manipulated by the stub in the usual way). For out and in, out parameters of a type that contain represent_as or one of its components, the named_type_free_local routine is automatically called for the data objects that contain the attribute. For in parameters, the named_type_free_local routine is only called if the represent_as attribute has been applied to the parameter. If the attribute has been applied to the components of the parameter, the *_free_local routine is not called. Freeing routines are not called for the embedded data and at-most-once call (related to the top-level attribute) for an in only parameter.

Note  It is possible to apply both the transmit_as and represent_as attributes to the same type. When marshalling data, the represent_as type conversion is applied first and then the transmit_as conversion is applied. The order is reversed when unmarshalling data. Thus, when marshalling, *_from_local allocates an instance of a named type and translates it from a local type object to the temporary named type object. This object is the presented type object used for the *_to_xmit routine. The *_to_xmit routine then allocates a transmitted type object and translates it from the presented (named) object to the transmitted object.

An array of long integers can be used to represent a linked list. In this way, the application manipulates the list and the transmission uses an array of long integers when a list of this type is transmitted. You can begin with an array, but using a construct with an open array of long integers is more convenient. The following example shows how to do this:

/* IDL definitions */
 
typedef struct_lbox {
    long        data;
    struct_lbox *        pNext
} LOC_BOX, * PLOC_BOX;
 
/* The definition of the local type visible to the application, 
as shown above, can be omitted in the IDL file. See the include 
in the ACF file. */
 
typedef struct_xmit_lbox {
    short        Size;
    [size_is(Size)] long DaraArr[];
} LONGARR;
 
void WireTheList( [in,out] LONGARR * pData );
 
/* ACF definitions */
 
/* If the IDL file does not have a definition for PLOC_BOX, you 
can still ready it for C compilation with the following include 
statement (notice that this is not a C include): 
include "local.h";*/
 
typedef [represent_as(PLOC_BOX)] LONGARR;
 

Note that the prototypes of the routines that use the LONGARR type are actually displayed in the STUB.H files as PLOC_BOX in place of the LONGARR type. The same is true of the appropriate stubs in the STUB_C.C file.

You must supply the folllowing four functions:

void __RPC_USER
LONGARR_from_local(
    PLOC_BOX __RPC_FAR * pList,
    LONGARR __RPC_FAR * _RPC_FAR * ppDataArr );
 
void __RPC_USER
LONGARR_to_local(
    LONGARR __RPC_FAR * _RPC_FAR * ppDataArr,
    PLOC_BOX __RPC_FAR * pList );
 
void __RPC_USER
LONGARR_free_inst(
    LONGARR __RPC_FAR * pDataArr);
 
void __RPC_USER
LONGARR_free_local(
    PLOC_BOX __RPC_FAR * pList );
 

The routines shown above do the following: