Profiling API Method Conventions
This topic discusses profiler callback return values and caller-allocated buffers.
A profiler returns a status value as an HRESULT for each notification that the common language runtime (CLR) raises. This status value may be S_OK or E_FAIL. Currently, the runtime ignores the status value in every callback except for the ICorProfilerCallback::ObjectReferences method.
HRESULT GetBuffer ( [in] /* Some query information (for example, a name).*/, [in] ULONG32 cBufferSizeStart, [out] ULONG32 *pcBufferMax, [out] /* TYPE */ InfoBuffer );
These methods always behave as follows:
The cBufferSizeStart parameter specifies the number of elements allocated in the buffer. This value represents the size of the buffer, which is allocated by the caller of this method.
The pcBufferMax parameter is set to the total number of available elements. After the method returns, pcBufferMax is set to the maximum number of elements that could have been returned instead of the number of elements that actually were returned. So, pcBufferMax is independent of the actual size of the caller-allocated buffer.
The InfoBuffer parameter specifies the caller-allocated buffer. It is created by the caller of this method. Its size is specified by cBufferSizeStart. After the method returns, this buffer will be filled with as many elements as possible. There may be more elements available than will fit into the buffer. If InfoBuffer is null, cBufferSizeStart must be 0. If any elements are returned, the method returns S_OK and sets pcBufferMax to the total number of elements available.
There are two ways to work with caller-allocated buffers:
Single-pass method: Allocate a buffer that you expect will be large enough to contain all the returned elements. Be prepared to reallocate the buffer if it proves to be too small. Otherwise, data truncation may occur.
Double-pass method: Alternatively, call the method two times. First call with a zero-length InfoBuffer parameter to obtain the correct buffer size. Then set the buffer size to the value returned in pcBufferMax and call the function again.
The first method is faster and avoids dynamic allocation. However, you may need to reallocate the buffer if it is not large enough to contain the information.
The second method is slower because it involves two calls and dynamic allocation. For example, let's assume that the requested query information was for an application domain's name. After this method returns, you must verify that InfoBuffer was large enough to contain the full name of the application domain. To do this, compare the value that pcBufferMax points to with the value of the cBufferSizeStart parameter. If pcBufferMax points to a value that is larger than cBufferSizeStart, allocate a larger InfoBuffer buffer, update cBufferSizeStart with the new, larger size, and call the method again.
In the profiling API, all output parameters (specified by [out] in the method syntax) are optional, unless a method has only one output parameter. A profiler passes null for any output parameters it is not interested in. The profiler must also pass consistent values for any input parameters that are associated with the output parameter. For example, if a null output parameter represents a buffer to be filled with data, the input parameter that specifies the buffer's size must be set to 0.