Retrieving Data of Unknown Length

Many functions return a potentially large amount of data to an address provided as one of the parameters by the application. 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 use the notation convention where pb or pv are 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 or pv location. For example, consider the following function specification:

#include <windows.h>

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

In this example, pbData is a pointer to 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 the 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 the GetLastError function) and stores the required buffer size, in bytes, in the variable pointed to by pcbData.

If NULL is input for pbData and pcbData is not NULL, no error is returned, and the function returns the size, in bytes, of the needed memory buffer 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 NULL is input for pbData to determine the size needed to ensure that the returned data fits in the specified buffer, 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. Use this size when processing the data.

 

The following example shows how input and output parameters might be implemented for this purpose.

//-------------------------------------------------------------------
// Copyright (C) Microsoft.  All rights reserved.
#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

void MyHandleError(char *s);

void main()
{

// Set up SomeFunction variables.
PCCRL_CONTEXT pCrlContext; // Initialized elsewhere.
DWORD dwPropId;            // Initialized elsewhere.
DWORD cbData;
BYTE  *pbData;

// Call SomeFunction to set cbData, the size of 
// the buffer needed for pbData.
if(SomeFunction(
     pCrlContext, 
     dwPropId, 
     NULL, 
     &cbData))
{
       printf("The function succeeded.\n");
}
else
{

// The function call failed. Handle the error.
       MyHandleError("Function call failed.");
}

// The call succeeded; the size for the needed buffer, in bytes, 
// now resides in cbData.

// Malloc memory for the size of the message.
if(pbData = (BYTE*)malloc(cbData))
{
   printf("Memory has been allocated.\n");
}
else
{

   // The allocation failed. Write an error message and exit.
   MyHandleError("Malloc operation failed. ");
}

// The space for the buffer has been allocated.
// Call SomeFunction to fill the buffer with the data.
if(SomeFunction(
      pCrlContext, 
      dwPropId, 
      pbData, 
      &cbData))
{
       printf("The function succeeded.\n");
}
else
{

   // The second function call failed. Handle the error.
   MyHandleError("The second call to the function failed.");
}

// The function succeeded; the data is now in the buffer
// pointed to by pbData. Note that cbData is
// updated with the actual size of the data returned. Use this size 
// to process bytes of pbData.

// When you have finished using the allocated memory, free it.
free(pbData);

} // End of main

//  This example uses the function MyHandleError, a simple error
//  handling function, to print an error message to the 
//  standard error (stderr) file and exit the program. 
//  For most applications, replace this function with one 
//  that does more extensive error reporting.
void MyHandleError(char *s)
{
    fprintf(stderr,"An error occurred in running the program.\n");
    fprintf(stderr,"%s\n",s);
    fprintf(stderr,"Error number %x.\n",GetLastError());
    fprintf(stderr,"Program terminating.\n");
    exit(1);
}