DECLARE @StartDate datetime,
        @EndDate   datetime,
        @days      int;
SET @StartDate = '20110129';
SET @EndDate   = '20110505';

-- get the number of days difference between the first of the month
-- of the starting and ending dates.
SET @days =  DATEDIFF(day, DateAdd(month, DateDiff(month, 0, @StartDate), 0),
                           DateAdd(month, DateDiff(month, 0, @EndDate), 0));

;WITH 
Tens     (N) AS (SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL 
                 SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL 
                 SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0), 
Thousands(N) AS (SELECT 1 FROM Tens t1 CROSS JOIN Tens t2 CROSS JOIN Tens t3), 
Millions (N) AS (SELECT 1 FROM Thousands t1 CROSS JOIN Thousands t2), 
Tally    (N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) FROM Millions),
CTE (StartDate, EndDate) AS
(
-- get the starting date and the end of the starting month
SELECT @StartDate, DateAdd(day, -1, DATEADD(month, 1 + DateDiff(month, 0, @StartDate), 0)) UNION ALL
-- get the start of the ending month and the ending date
SELECT DATEADD(month, DateDiff(month, 0, @EndDate), 0), @EndDate UNION ALL
-- get the start and end of all months between
SELECT DATEADD(month, DateDiff(month, 0, @StartDate) + N, 0),
       DATEADD(day, -1, DATEADD(month, 1+DateDiff(month, 0, @StartDate) + N, 0))
  FROM Tally
 WHERE N < DATEDIFF(MONTH, @StartDate, @EndDate)
)
-- if @days > 0, then specified dates cross at least one 
-- month boundary, so get everything from the CTE
SELECT [Year] = YEAR(StartDate), 
       [Month] = MONTH(StartDate), 
       [Days] = DATEDIFF(day, StartDate, EndDate)+1
  FROM CTE
 WHERE @days > 0
UNION ALL
-- if @days = 0, then specified dates are in the same month
-- so get just this information.
SELECT YEAR(@StartDate),
       MONTH(@StartDate),
       DATEDIFF(day, @StartDate, @EndDate)+1
 WHERE @days = 0         
 ORDER BY [Year], [Month];