You can make things more concise with LINQ.  Here's one way that should work:

    List<Control> getControls(Control container, Rectangle rect, bool bContained = false)
    {
        rect = RectangleToClient(rect);
        return (from Control ctl in container.Controls
                      where rect.IntersectsWith(ctl.Bounds) == bContained
                      let ctls = new List<Control> { ctl }.Union(ctl.Controls.OfType<Control>())                     
                      select ctls).SelectMany(x => x).ToList();
    }

This basically does the same thing, filters the collection according to `bContained`.  Creates a collection of  lists that each contain the parent control and its sub-controls.  Then flattens them into one list.