How do I implement a virtual grid? I want to supply cell contents on demand.

Here is an example how you can override GetStyleRowCol and StoreStyleRowCol and implement a virtual grid. See also the browsevw.cpp/.h sample in gridapp.

BOOL CBrowserView::GetStyleRowCol(ROWCOL nRow, ROWCOL nCol, CGXStyle& style, GXModifyType mt, int nType)
{
   if (mt == gxRemove) // not supported
      return FALSE;
   // Note: I do not distinct between gxApplyNew, gxCopy and gxOverride
   ASSERT(nRow <= LONG_MAX);
   long nRecord = (long) nRow;
   if (nType == -1)
   {
      // here you can return the style for a complete row, column or table
      return FALSE;
   }
   else if (nRow == 0 && nCol == 0)
   {
      // style for the top-left button
      return FALSE;
   }
   else if (nRow == 0)
   {
      // Column headers
      style.SetValue(nCol);
   }
   else 
   {
      // Cell in the grid
      style.SetValue(myData[nRow][nCol].text);
      // - Or -
      style.SetValue("World");
      return TRUE;
   }
   return FALSE;
}

You should also override StoreStyleRowCol to store the value in your data structure if the user did change it.  The grid always calls this method to store values.

Example:

BOOL CBrowserView::StoreStyleRowCol(ROWCOL nRow, ROWCOL nCol, const CGXStyle* pStyle, GXModifyType mt, int nType)
{
   if (mt == gxRemove) // not supported
      return FALSE;
   // Note: I do not distinct between gxApplyNew, gxCopy and gxOverride
   if (nType == -1)
   {
      // here you could store the style for a complete row, column or table
      return FALSE;
   }
   else if (nRow == 0 && nCol == 0)
   {
      // style for the top-left button
      return FALSE;
   }
   else if (nRow == 0)
   {
      // Column headers
      return FALSE;
   }
   else 
   {
      // cell
      myData[nRow][nCol].text = style.GetValue();
      return TRUE;
   }
   // unreferenced:
   mt;
   return FALSE;
}

You might also override GetRowCount() to return the number of rows in your data structure.

Example:

ROWCOL CBrowserView::GetRowCount()
{
      return myData.GetRowCount();
}

When the grid starts drawing any cells, it loads all cells it needs to draw into memory.  At this time the GetStyleRowCol method will be called for each cell.  The grid keeps all the cells of the last drawing action in memory until the next drawing action occurs.  Then, it frees the memory and loads the new cells that need to be drawn.