title: COleSafeArray / VARIANT memory leak?
body: <p>I want to export a lot of (table) data to Excel. I'm developing on Windows Xp, Vs2005. I'm filling a COleSafeArray, which was initialized like this:</p>
  
  <pre><code>safeArray.Create( VT_VARIANT, 2, numElements ); // 2 dimensional, 30000 rows, 3 columns
  </code></pre>
  
  <p>Now the filling is really fast, but in TaskManager/Process Explorer/VMMap, it looks like some of the memory does not get released properly (VMMap still finds my dummy strings in the memory). I tried the tips (disabling BSTR caching) from the following pages, but had no success so far:<br>
  <a href="https://devblogs.microsoft.com/oldnewthing/20091127-00/?p=15883" rel="nofollow noreferrer">https://devblogs.microsoft.com/oldnewthing/20091127-00/?p=15883</a><br>
  <a href="http://blogs.msdn.com/larryosterman/archive/2004/09/28/235304.aspx" rel="nofollow noreferrer">http://blogs.msdn.com/larryosterman/archive/2004/09/28/235304.aspx</a></p>
  
  <p>Is there still the caching taking place (I've set the environment variable OANOCACHE = 1), or is there something wrong with my code? </p>
  
  <p>Note: This is part of a MFC dialog based non-unicode application.</p>
  
  <pre><code>//-----------------------------------------------------------------------------
  template&lt; typename _ValueType &gt;
  void setSafeArrayElement( const _ValueType&amp; value, 
                            const int row, 
                            const int column, 
                            COleSafeArray&amp; safeArray
                           )
  {
    VARIANT variant;
    VariantInit(&amp;variant);
    {
      COleVariant oleVariant = value;  
      variant = oleVariant;
      oleVariant.Detach();
    }
    long coordinates[2] = { row, column };
    safeArray.PutElement( coordinates, &amp;variant );
    VariantClear(&amp;variant);
  }
  
  //-----------------------------------------------------------------------------
  #define XL_CELLTYPE_TEXT        "@"
  #define XL_CELLTYPE_DOUBLE2     "#'##0.00"
  #define XL_CELLTYPE_DOUBLE3     "#'##0.000"
  #define XL_CELLTYPE_DOUBLE4     "#'##0.0000"
  #define XL_CELLTYPE_DOUBLE6     "#'##0.000000"
  #define XL_CELLTYPE_DOUBLE8     "#'##0.00000000"
  #define XL_CELLTYPE_NUMBER      "0"
  #define XL_CELLTYPE_NUMBER1000  "#'##0"
  #define XL_CELLTYPE_DATE        "TT.MM.JJJJ"
  #define XL_CELLTYPE_GENERAL     "Standard"
  
  //-----------------------------------------------------------------------------
  void CexcelTestDlg::OnBnClickedButton2()
  {
    const bool closeExcel = true;
    const int rows = 30000;
    const int columns = 3;
  
    //AfxOleGetMessageFilter()-&gt;SetMessagePendingDelay( x );
    AfxOleGetMessageFilter()-&gt;EnableNotRespondingDialog( FALSE );
    AfxOleGetMessageFilter()-&gt;EnableBusyDialog( FALSE );
  
    Excel11::_ApplicationPtr    app;
    Excel11::WorkbooksPtr       books;
    Excel11::_WorkbookPtr       book;
    Excel11::SheetsPtr          sheets;
    Excel11::_WorksheetPtr      sheet;
    app.CreateInstance( "Excel.Application" );
    try
    {
      //app-&gt;Visible        = VARIANT_TRUE;
      app-&gt;Visible        = VARIANT_FALSE;
      app-&gt;Interactive    = VARIANT_FALSE;
      app-&gt;UserControl    = VARIANT_FALSE;
      app-&gt;ScreenUpdating = VARIANT_FALSE;
      app-&gt;DisplayAlerts  = VARIANT_FALSE;
      books           = app-&gt;GetWorkbooks();    // all open files
      book            = books-&gt;Add();           // add new file
      sheets          = book-&gt;Sheets;           // all worksheets
  
      try 
      {
        COleSafeArray safeArray;
        DWORD numElements[] = { rows, columns };
        safeArray.Create( VT_VARIANT, 2, numElements );
  
        // rename default worksheet
        Excel11::_WorksheetPtr
        sheet1          = sheets-&gt;GetItem(1);
        sheet1-&gt;Name    = "Blah"; 
  
        // format columns
        {
          std::string coords = getExcelCoordinates( 0, 0 );   // getExcelCoordinates returns strings like "A1", "F23", ... (excel cell coordinates)
          Excel11::RangePtr range = sheet1-&gt;Range[coords.c_str()][coords.c_str()];
          range = range-&gt;EntireColumn;
          range-&gt;NumberFormat = XL_CELLTYPE_TEXT;
  
          coords = getExcelCoordinates( 0, 1 );
          range = sheet1-&gt;Range[coords.c_str()][coords.c_str()];
          range = range-&gt;EntireColumn;
          range-&gt;NumberFormat = XL_CELLTYPE_DATE;
  
          coords = getExcelCoordinates( 0, 2 );
          range = sheet1-&gt;Range[coords.c_str()][coords.c_str()];
          range = range-&gt;EntireColumn;
          range-&gt;NumberFormat = XL_CELLTYPE_DOUBLE2;
        }
  
        // fill line by line
        for( int row = 0; row &lt; rows; ++row )
        {        
          CString rowName;
          rowName.Format( "%d", row + 1 );        
          // Text
          CString v0 = CString( "Wusel Dusel " ) + rowName;
          setSafeArrayElement( v0, row, 0, safeArray );        
          // Date
          CString v1 = "11.12.1975";
          setSafeArrayElement( v1, row, 1, safeArray );
          // Number
          double v2 = 123.45;
          setSafeArrayElement( v2, row, 2, safeArray );
        }
  
        // export safearray to excel
        if( rows )
        {
          const std::string   cellCoordTopLeft      = getExcelCoordinates( 0, 0 );
          const std::string   cellCoordBottomRight  = getExcelCoordinates( rows-1, columns-1 );
  
          Excel11::RangePtr range = sheet1-&gt;Range[ cellCoordTopLeft.c_str(), cellCoordBottomRight.c_str()];      
          COleVariant         vtOptional((long)DISP_E_PARAMNOTFOUND,VT_ERROR);
          // export the whole safeArray contents to excel
          range-&gt;PutValue( vtOptional, COleVariant( safeArray ) );
        }
  
        // optimize column widths
        Excel11::RangePtr cells = sheet1-&gt;Cells;
        cells-&gt;Select();
        cells-&gt;EntireColumn-&gt;AutoFit();
        Excel11::RangePtr singleCell = sheet1-&gt;Range["A1"]["A1"];
        singleCell-&gt;Select();
  
        // clear safeArray
        VARIANT* varPtr = 0;
        try 
        {
          // Get a pointer to the elements of the array
          // and increments the lock count on the array
          safeArray.AccessData((LPVOID*)&amp;varPtr);
          for( int i = 0; i &lt; rows * columns; ++i )
          {
            VARIANT&amp; vp = varPtr[i];
            VariantClear( &amp;vp );
          }
          //decrement lock count
          safeArray.UnaccessData();
        }
        catch (COleException *pEx)
        {
          AfxThrowOleDispatchException(1003, _T("Unexpected Failure in FastSort method"));
          pEx-&gt;Delete();
        }
        //safeArray.DestroyData();            //???
        //safeArray.DestroyDescriptor();    //???  
        safeArray.Clear();
      }
      catch( std::exception&amp; err )
      {
        MessageBox( err.what() );
      }
  
      if( closeExcel )
      {
        book-&gt;Close( VARIANT_FALSE );   // close the file
        app-&gt;Quit();                    // close Excel instance
      }
      else
      {
        app-&gt;Visible        = VARIANT_TRUE;
        app-&gt;Interactive    = VARIANT_TRUE;
        app-&gt;UserControl    = VARIANT_TRUE;
        app-&gt;ScreenUpdating = VARIANT_TRUE;
        app-&gt;DisplayAlerts  = VARIANT_TRUE;
      }
      app.Release();
    }
    catch( _com_error&amp; err )
    {
      CString s(err.Description().GetBSTR());
      MessageBox(s);
    }
  
  }
  </code></pre>