Home » excel » c# – Generate a flat list of all excel cell formulas

c# – Generate a flat list of all excel cell formulas

Posted by: admin April 23, 2020 Leave a comment

Questions:

I have a massive program written with VBA and cell formulas. I am tasked to reverse engineer it into C# winforms. I figured for a start, I need to see all the cell formulas in a flat list.

Any existing way to do it? Thanks in advance!

EDIT: Just to share, with the help of answerers, I managed to come up with this:

Excel formula browser lets you view precedents in a tree view.

How to&Answers:

in VBA (easily modifiable to vbscript) you could quickly dump all formulae in all sheets to a flat txt file (change your path to suit) with an efficient variant array. code sourced from my article here

Const sFilePath = "C:\test\myfile.txt"    

Sub CreateTxt_Output()
    Dim ws As Worksheet
    Dim rng1 As Range
    Dim X
    Dim lRow As Long
    Dim lCol As Long
    Dim strTmp As String
    Dim lFnum As Long

    lFnum = FreeFile
    Open sFilePath For Output As lFnum

    For Each ws In ActiveWorkbook.Worksheets
    Print #lFnum, "*****" & ws.Name & "*****"
        'test that sheet has been used
        Set rng1 = ws.UsedRange
        If Not rng1 Is Nothing Then
            'only multi-cell ranges can be written to a 2D array
            If rng1.Cells.Count > 1 Then
                X = ws.UsedRange.Formula
                For lRow = 1 To UBound(X, 1)
                    For lCol = 1 To UBound(X, 2)
                        'write each line to txt file
                        Print #lFnum, X(lRow, lCol)
                    Next lCol
                Next lRow
            Else
                Print #lFnum, rng1.Formula
            End If
        End If
    Next ws

    Close lFnum
    MsgBox "Done!", vbOKOnly
End Sub

[Updated section – you can isolate formulae quickly in VBA by using SpecialCells. Error Handling is needed in case there are no formulae on a sheet, see GetFormula below

Sub GetFormula()
    Dim ws As Worksheet
    Dim rng1 As Range
    Dim rng2 As Range
    For Each ws In ActiveWorkbook.Sheets
    Set rng1 = Nothing
        On Error Resume Next
        Set rng1 = ws.Cells.SpecialCells(xlCellTypeFormulas)
        On Error GoTo 0
        If Not rng1 Is Nothing Then
            For Each rng2 In rng1.Areas
            'dump cells here
            Next rng2
        End If
    Next ws
End Sub

Answer:

Here is some code that I used to get a list of cells on a worksheet with formulas in them. It seems pretty fast.

try
{
    Excel.Worksheet excelWorksheet = workbook.ActiveSheet as Excel.Worksheet;
    Excel.Range formulaCell = excelWorksheet.Cells.SpecialCells(
        Excel.XlCellType.xlCellTypeFormulas, Type.Missing);

    Excel.Range cell;
    foreach (var fc in formulaCell)
    {
        cell = fc as Excel.Range;
        string s1 = cell.Formula as string;
        int c = cell.Column;
        int r = cell.Row;

        // Gives formula text and location of formula.
    }
}
catch (Exception)
{
    ; // Throws an exception if there are no results.
      // Probably should ignore that exception only
}

Answer:

The key combination ctrl+` (back tick) toggles between viewing values and formulas, it is not a flat list, but it is useful.

Answer:

With help from brettdj, I managed to whip up a quad tree search at the moment

private static void FindFormula(Excel excel, TextWriter writer, int rowstart, int rowend, int colstart, int colend)
{
    // Select the range
    excel.Range(rowstart, rowend, colstart, colend);

    // Check whether this range has formulas
    if (!excel.RangeHasFormula())
        return;

    // Check if we only have a single cell
    if (excel.RangeCellCount() == 1)
    {
        Console.WriteLine(excel.CellFormula(rowstart, colstart));
        return;
    }

    int r1, r2, r3, r4;
    int c1, c2, c3, c4;

    r1 = rowstart;
    r2 = rowstart + (rowend - rowstart + 1) / 2 - 1;
    r3 = r2 + 1;
    r4 = rowend;

    if (colstart == colend)
    {
        c1 = c2 = c3 = c4 = colstart;

        FindFormula(excel, writer, r1, r2, c1, c2);
        FindFormula(excel, writer, r3, r4, c1, c2);
    }
    else
    {
        c1 = colstart;
        c2 = colstart + (colend - colstart + 1) / 2 - 1;
        c3 = c2 + 1;
        c4 = colend;

        FindFormula(excel, writer, r1, r2, c1, c2);
        FindFormula(excel, writer, r1, r2, c3, c4);
        FindFormula(excel, writer, r3, r4, c1, c2);
        FindFormula(excel, writer, r3, r4, c3, c4);
    }
}

Answer:

I found this answer, and tried to use the C# code by @Jake, but discovered it was slow.

Here is a faster (and complete) version:

using System;
using System.Text;
using Microsoft.Office.Interop.Excel;

namespace ExportExcelFormulas
{
    static class ExcelAccess
    {
        public static void ExportFormulasSimple(string filePath)
        {
            var app = new Application();
            var workbook = app.Workbooks.Open(filePath);
            var sCount = workbook.Sheets.Count;

            var sb = new StringBuilder();

            for (int s = 1; s <= sCount; s++)
            {
                var sheet = workbook.Sheets[s];
                var range = sheet.UsedRange;
                var f = range.Formula;

                var cCount = range.Columns.Count;
                var rCount = range.Rows.Count;

                for (int r = 1; r <= rCount; r++)
                {
                    for (int c = 1; c <= cCount; c++)
                    {
                        var id = ColumnIndexToColumnLetter(c) + "" + r + ": ";
                        var val = f[r, c];

                        if (!string.IsNullOrEmpty(val))
                        {
                            sb.AppendLine(id + val);
                            Console.WriteLine(id + val);
                        }

                    }
                }

            }

            var text = sb.ToString();
        }

        // Based on https://www.add-in-express.com/creating-addins-blog/2013/11/13/convert-excel-column-number-to-name/
        public static string ColumnIndexToColumnLetter(int i)
        {
            var l = "";
            var mod = 0;

            while (i > 0)
            {
                mod = (i - 1) % 26;
                l = (char)(65 + mod) + l;
                i = (int)((i - mod) / 26);
            }

            return l;
        }
    }
}