Common In/Out Parameter Conventions

Many of the functions return a potentially large amount of data to an address provided in one of the parameters by the application program. In all these cases, the operation is performed in a similar, if not identical, fashion. The parameter that points to the location of the returned data will have the notation convention where "pb" is the first two characters of the parameter name. Another parameter will have "pcb" as the first three characters of the parameter name. This parameter represents the size, in bytes, of the data that will be returned to the "pb" location. For example, consider the following function specification:

BOOL WINAPI SomeFunction(
  PCCRL_CONTEXT pCrlContext,  // in
  DWORD dwPropId,             // in
  BYTE *pbData,               // out
  DWORD *pcbData              // in/out
);
 

In this example pbData is the location where the data will be returned, and pcbData is the size, in bytes, of the returned data.

Note  The companion parameter to the "pcb" parameter may sometimes carry a slightly different prefix, such as "p" or "pv".

Also, for companion parameters using the combination of prefixes:"pwsz" and "pcch", the "pcch" parameter is the count in characters (UNICODE or ASCII, as applicable), of the returned data.

If the buffer specified by pbData parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code (which can be seen by calling GetLastError), and stores the required buffer size, in bytes, into the variable pointed to by pcbData.

If pbData is NULL, and pcbData is non-NULL, then no error is returned and the function returns the size of the needed memory buffer, in bytes, in the variable pointed to by pcbData. This lets an application determine the size of, and the best way to allocate, a buffer for the returned data.

Note  When pbData = NULL is used to determine the size needed to insure that the returned data fits in the specified buffer, it should be noted that the second call to the function (which populates the buffer with the desired data) may not use the whole buffer. After the second call, the actual size of the data returned is contained in pcbData, and it is this size that should be used when processing the data.

See Efficient Use of Common In/Out Parameter Conventions for information on optimizing performance when using this convention.

The following example code demonstrates how this operation might be implemented:

// Assume that the application has already declared and initialized all 
// the necessary variables.

// Call SomeFunction() to get the size of the returned data. 
BOOL        fReturn =            FALSE;

fReturn = SomeFunction(pCrlContext, dwPropId, NULL, &cbData);
if(fReturn != TRUE)
    ;// Function call failed.  Handle the error.

// If the call succeeded, the size of the data, in bytes, 
// now resides in cbData.

// Malloc memory for the size of the message.
BYTE* pbData;

pbData = (BYTE*)malloc(cbData);
if(pbData = NULL)
    ;// Handle the memory allocation error.

// Call SomeFunction() to return the data.

fReturn = SomeFunction(pCrlContext, dwPropId, pbData, &cbData);
if(fReturn != TRUE)
    ;// Function call failed.  Handle the error.

// If the function succeeded, the data is now at the location pointed 
// to by pbData. Note that cbData is updated with the actual size of 
// the data returned, and it is this size that should be used when 
// processing the data.