2.2 Common Data Types
The Print System Remote Protocol MUST indicate to the RPC runtime that it is to support both the Network Data Representation (NDR) and NDR64 RPC transfer syntaxes and provide a negotiation mechanism for determining which transfer syntax is used ([MS-RPCE] section 3).
This protocol MUST enable the ms_union extension ([MS-RPCE] section 2.2.4).
The Print System Remote Protocol employs a combination of the following data representations:
IDL data structures used with RPC methods, including structures used as containers for custom-marshaled, custom C data (section 2.2.1).
Custom C data structures and their wire formats used within custom marshaled data streams (section 2.2.2).
Unless noted otherwise, the following statements apply to this specification:
All strings defined in this protocol MUST consist of characters encoded in Unicode UTF-16LE and MUST be null-terminated. Each UTF-16 codepoint in a string, including terminating null characters, MUST occupy 16 bits ([RFC2781], section 2.1).
A list of strings is referred to as a multisz in this protocol. In a multisz, the characters making up the string N+1 MUST directly follow the terminating null character of string N. The last string in a multisz MUST be terminated by two null characters.
All parameters or members specifying the number of characters in a string or multisz specify the number of characters including terminating null characters.
All constraints specifying the maximum number of characters in a string or multisz specify the number of characters including terminating null characters.
All parameters or members specifying the number of bytes in buffers containing a string or multisz specify the number of bytes including terminating null characters.
Custom-marshaled data that consists of more than a single byte is specified in little-endian byte order.
The term NULL means a NULL pointer, and zero means the number 0.
All parameters or members specifying the size of a buffer pointed to by another parameter or member MUST be zero if the pointer parameter or member is NULL.
The term "empty string" means a string containing only the terminating null character.
The term "optional pointer" means that providing a pointer value in the parameter or member is optional. If the pointer value is not provided, the value of the parameter or member MUST be NULL.
This protocol specification uses curly braced GUID strings ([MS-DTYP] section 2.3.4.3).
This protocol introduces a variety of data types that bundle information about printers, printer drivers, print jobs, and ports. These data types are collectively referred to as INFO data types, and include DRIVER_INFO_1 (section 2.2.1.5.1), PRINTER_INFO_1 (section 2.2.1.10.2), JOB_INFO_1 (section 2.2.1.7.1), and PORT_INFO_1 (section 2.2.1.9.1). As data types were refined in the evolution of this protocol, new INFO data type versions have been introduced to represent extended or different bundles of information. The term "level" is used to differentiate between the different type versions, and the number of the level is reflected in the name of the data type, for example, JOB_INFO_1, JOB_INFO_2, and JOB_INFO_3.
To simplify method parameter lists and to increase robustness of RPC marshaling, the protocol introduces CONTAINER data types, which consolidate the input parameters used by RPC methods. Some CONTAINER data types hold a Level value along with a union of pointer values pointing to different INFO data type versions; the specific Level values available for each CONTAINER data type are documented in section 2.2.1.2. For example, a JOB_CONTAINER (section 2.2.1.2.5) contains a level value and a union of pointers to the different JOB_INFO data type versions, which are selected by the Level value. Other CONTAINER data types hold a pointer value that points to a structure, along with a numerical value representing the size of the structure. For example, a DEVMODE_CONTAINER (section 2.2.1.2.1) contains a size value and a pointer to a custom-marshaled structure. Finally, several CONTAINER data types hold a version value, a value representing a set of flags, an array of structures, and a value representing the number of elements in the array. The RPC_BIDI_REQUEST_CONTAINER (section 2.2.1.2.10) is an example of a CONTAINER data type in this category.
Most of the INFO data types have an IDL form and a custom-marshaled form. IDL forms can be used in conjunction with CONTAINER data types, as input parameters to methods that set values, such as RpcSetPrinter (section 3.1.4.2.5), while custom-marshaled forms can be used as output parameters to methods that get values, such as RpcGetPrinter (section 3.1.4.2.6). The layout and order of members of IDL forms are in most cases the same as those of corresponding custom-marshaled forms, with the distinction that IDL forms use the type "[string] wchar_t *" to point to strings, while custom-marshaled forms use an offset relative to the start of the structure.
As an exception to the preceding rule, the layout of IDL-marshaled structures that contain pointers to multisz data differs from the layout of custom-marshaled forms, in that IDL-marshaled structures need to define a length member for each IDL-marshaled member of type pointer to multisz; the names of such IDL-marshaled members start with RPC_.
To increase clarity, an underscore has been prepended to the names of all custom-marshaled structures, for which an IDL-marshaled form exists. For example, _DRIVER_INFO_1 is the name of the custom-marshaled structure that corresponds to DRIVER_INFO_1, the IDL-marshaled form.
When IDL-marshaled structures that contain pointer types to variable-length data without field IDL attributes [MSDN-FIELD], such as [string] or [size_is(...)], are used as input arguments to methods, either directly or in CONTAINER structures, the pointers and variables to which they point cannot be marshaled by RPC, because RPC does not know the length of the data that is pointed to. Examples are the pSecurityDescriptor and pDevMode members of the PRINTER_INFO_2 structure.
To address this problem, methods that specify such input arguments accept separate CONTAINER structures that pass in custom-marshaled or self-relative forms of the pointers and the variables that they reference. Examples of such methods are RpcSetPrinter and RpcAddPrinterEx (section 3.1.4.2.15). Individual method sections specify how affected pointer members and CONTAINER structures MUST be treated.