A memory leak occurs when you run a CDO application that is written in C++ (887805)



The information in this article applies to:

  • Collaboration Data Objects (CDO), when used with:
    • Microsoft Visual C++ 2005 Express Edition
    • Microsoft Visual C++ .NET (2003)
    • Microsoft Visual C++ .NET (2002)
    • Microsoft Visual C++, 32-bit Professional Edition 6.0
    • Microsoft Visual C++ Standard Edition, version 6.0

SYMPTOMS

When you run a Collaborative Data Objects (CDO) application that is written in Microsoft C++, a memory leak occurs. The memory usage of the CDO application process may grow steadily over a long time. Additionally, a gradual decrease in application performance may occur. Over time, the value of the Private Bytes counter for the CDO application may continue to increase.

CAUSE

This problem can occur when the application uses CDO to access a field in a message. Error objects may not be disposed of correctly when the following conditions are true:
  • A call to the get_Value method successfully returns.
  • The VARIANT parameter that is passed into the get_Value method has the Variant type (vt) set to VT_EMPTY when the method returns.
This causes the memory leak.

RESOLUTION

To resolve this problem, test for the current error object by calling the GetErrorInfo method, and then dispose of the errors accordingly. The following is a code example.
if( SUCCEEDED( hr = field->get_Value( &value )))
{
	if( value.vt == VT_EMPTY )
	{
		CheckErrors();
	}
	else
	{
		// Do something useful with the information.
	}
}


void CheckErrors()
{
    IErrorInfo*         pErrorInfo = NULL;
    IErrorInfo*         pErrorInfoRec = NULL;
    IErrorRecords*      pErrorRecords = NULL;
    ULONG               i, ulNumErrorRecs = 0;
    ERRORINFO           ErrorInfo = {0};
    DWORD               MYLOCALEID = 0x409;
    HRESULT             hRes = S_OK;
    
    // Obtain the current error object. Return if no
    // error object exists.
    hRes = GetErrorInfo(0,&pErrorInfo);
    if (!pErrorInfo) return;
    
    // Obtain the IErrorRecord interface, and then obtain the count
    // of error records.
    hRes = pErrorInfo->QueryInterface(IID_IErrorRecords, (void**)&pErrorRecords);
    if (pErrorRecords)
    {
        pErrorRecords->GetRecordCount(&ulNumErrorRecs);
        
        // Read through error records and display them.
        for (i = 0; i < ulNumErrorRecs; i++) 
        {
            // Get basic error information.
            pErrorRecords->GetBasicErrorInfo(i, &ErrorInfo);
            
            // Get error description and source through the
            // IErrorInfo interface pointer on a particular record.
            pErrorRecords->GetErrorInfo(i, MYLOCALEID, &pErrorInfoRec);
            if (pErrorInfoRec)
            {
                BSTR bstrDescriptionOfError = NULL;
                BSTR bstrSourceOfError = NULL;
                
                hRes = pErrorInfoRec->GetDescription(&bstrDescriptionOfError);
                hRes = pErrorInfoRec->GetSource(&bstrSourceOfError);
                
                // At this point, you can call GetCustomErrorObject
                // and query for additional interfaces to determine
                // what else occurred.
                
                wprintf(
                    OLESTR("HRESULT    : %lx\r\nMinor Code : %lx\r\nSource     : %s\r\nDescription: %s\n"),
                    ErrorInfo.hrError,
                    ErrorInfo.dwMinor,
                    bstrSourceOfError,
                    bstrDescriptionOfError);
                
                // Free the resources.
                SysFreeString(bstrDescriptionOfError);
                SysFreeString(bstrSourceOfError);
                pErrorInfoRec->Release();
            }
        }
        pErrorRecords->Release();
    }
    pErrorInfo->Release();
}

MORE INFORMATION

You can generally confirm whether a memory leak exists by monitoring the following counter in Performance Monitor:
Performance Object: Process
Instance: YourApplication.exe 
Counter: Private Bytes 
Note YourApplication.exe is a placeholder for the name of the C++ application.

Modification Type:MajorLast Reviewed:5/2/2006
Keywords:kbCDO kbExpertiseInter kbtshoot kbcode KB887805 kbAudDeveloper