/// <summary>
    /// Gets the macros from the system
    /// </summary>
    /// <param name="startIndex">Start index</param>
    /// <param name="endIndex">End index</param>
    /// <param name="maxTotalRecords">Maximum number of total records to process</param>
    /// <param name="totalRecords">Returns the total number of records found</param>
    private IEnumerable <MacroExpr> GetMacros(int startIndex, int endIndex, int maxTotalRecords, out int totalRecords)
    {
        var index = 0;

        var textToSearch       = txtTextToSearch.Text;
        var searchByText       = !String.IsNullOrEmpty(textToSearch);
        var reportProblems     = chkReportProblems.Checked;
        var skipTestingObjects = SystemContext.DevelopmentMode && chkSkipTestingObjects.Checked;
        var type = drpType.Text;

        var result = new List <MacroExpr>();

        foreach (var objectType in GetObjectTypes())
        {
            // Skip certain object types
            switch (objectType)
            {
            case ObjectVersionHistoryInfo.OBJECT_TYPE:
            case VersionHistoryInfo.OBJECT_TYPE:
            case StagingTaskInfo.OBJECT_TYPE:
            case IntegrationTaskInfo.OBJECT_TYPE:
                continue;
            }

            // Process all objects of the given type
            var infos = new ObjectQuery(objectType)
                        .TopN(maxTotalRecords)
                        .BinaryData(false);

            var typeInfo = infos.TypeInfo;

            if (skipTestingObjects)
            {
                ExcludeTestingObjects(infos);
            }

            // Search particular expression or search macros of specific type
            infos.WhereAnyColumnContains(searchByText ? textToSearch : "{" + type);

            Action <DataRow> collectMacros = dr =>
            {
                // Process all expressions
                MacroProcessor.ProcessMacros(new DataRowContainer(dr), (context, colName) =>
                {
                    // Get original macro text with hash
                    string macroType;
                    string originalExpression  = MacroProcessor.RemoveMacroBrackets(context.GetOriginalExpression(), out macroType);
                    string processedExpression = context.Expression;

                    // Decode macro from XML if needed
                    if (MacroProcessor.IsXMLColumn(colName))
                    {
                        originalExpression  = HTMLHelper.HTMLDecode(originalExpression);
                        processedExpression = HTMLHelper.HTMLDecode(processedExpression);
                    }

                    MacroExpr e = null;
                    bool add    = false;

                    if (!searchByText || (originalExpression.IndexOf(textToSearch, StringComparison.InvariantCultureIgnoreCase) >= 0))
                    {
                        // If not tracking errors, count immediately
                        if (!reportProblems)
                        {
                            // Apply paging. (endIndex is -1 when paging is off)
                            if ((endIndex < 0) || ((index >= startIndex) && (index < endIndex)))
                            {
                                e   = GetMacroExpr(originalExpression, processedExpression);
                                add = true;
                            }

                            index++;
                        }
                        else
                        {
                            e = GetMacroExpr(originalExpression, processedExpression);

                            // Filter invalid signature / syntax
                            if (!e.SignatureValid || e.Error)
                            {
                                // Apply paging. (endIndex is -1 when paging is off)
                                if ((endIndex < 0) || ((index >= startIndex) && (index < endIndex)))
                                {
                                    add = true;
                                }

                                index++;
                            }
                        }
                    }

                    if (add)
                    {
                        // Fill in the object information
                        e.ObjectType = objectType;
                        e.ObjectID   = (typeInfo.IDColumn == ObjectTypeInfo.COLUMN_NAME_UNKNOWN) ? 0 : ValidationHelper.GetInteger(dr[typeInfo.IDColumn], 0);
                        e.Field      = colName;

                        result.Add(e);
                    }

                    return(context.Expression);
                }, new List <string> {
                    type
                });

                if ((maxTotalRecords != -1) && (index >= maxTotalRecords))
                {
                    // Enough data - cancel enumeration
                    throw new ActionCancelledException();
                }
            };

            using (var scope = new CMSConnectionScope())
            {
                scope.CommandTimeout = ConnectionHelper.LongRunningCommandTimeout;

                infos.ForEachRow(collectMacros);
            }

            if (((maxTotalRecords != -1) && (index >= maxTotalRecords)) || !CMSHttpContext.Current.Response.IsClientConnected)
            {
                break;
            }
        }

        totalRecords = index;
        return(result);
    }