C# - Having trouble with Excel/InteropServices Replace Method

1

So searching has returned some results on how to use the Replace method, but I haven't gotten any to work. Hoping you guys can help point me in the right direction!

Here's what I have. I get an error when I call the Replace method. I suspect I'm doing something wrong with the Range, but am not sure.

private Process DoExcelWork(Process excelProc, string filePath)
{
    // Initialize Excel Application
    Excel.Application excelApp = new Excel.Application();
    excelApp.Visible = false;

    // Get the process
    Process[] possibleProcesses = Process.GetProcessesByName("Excel");
    excelProc = possibleProcesses[0];

    // Empty Object for optional arguments
    object optional = System.Reflection.Missing.Value;

    Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(filePath, optional, optional, optional, optional, optional, optional, optional, optional, optional, optional, optional, optional, optional, optional);

    // Seems to be necessary to do stuff to the file
    excelWorkbook.VBProject.References.AddFromGuid("{0002E157-0000-0000-C000-000000000046}", 5, 3);

    foreach (Excel.Worksheet excelWorksheet in excelWorkbook.Worksheets)
    {
        Excel.Range lastCell = excelWorksheet.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, optional);
        Excel.Range excelRange = excelWorksheet.get_Range("A1", lastCell);

        excelRange.Replace("Blue", "Red", Excel.XlLookAt.xlPart, Excel.XlSearchOrder.xlByRows, false, optional, optional, optional);
    }                   

    excelWorkbook.Save();
    excelWorkbook.Close(0);

    // Quit Excel 
    excelApp.Quit();

    // Release
    NAR(excelApp);

    return excelProc;
} 

Here's the error:

System.Runtime.InteropServices.COMException (0x800706BE): The remote procedure call failed. (Exception from HRESULT: 0x800706BE) at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData) at Microsoft.Office.Interop.Excel.Range.Replace(Object What, Object Replacement, Object LookAt, Object SearchOrder, Object MatchCase, Object MatchByte, Object SearchFormat, Object ReplaceFormat)

c#
asp.net
excel
excel-interop
asked on Stack Overflow Jul 4, 2014 by Karl • edited Jul 5, 2014 by (unknown user)

1 Answer

0

So I never did get this to work. I suspect Microsoft not supporting server-side automation of this sort has something to do with it.

I ended up doing a work-around, where I iterate through each cell and manually update the value (if the search criteria is met). In my case, I was only looking for cells that have formulas in them, so I do some other things as well. But here's what I ended up going with:

// Initialize Excel Application
Excel.Application excelApp = null;
excelApp = new Excel.Application();
excelApp.Visible = false;
excelApp.DisplayAlerts = false;

// Get the process. Not as precise as would like, but probably the best we can get from an .ASP call
Process[] possibleProcesses = Process.GetProcessesByName("Excel");
excelProc = possibleProcesses[0];

// Object for optional arguments when creating Excel Workbook
object optional = System.Reflection.Missing.Value;

Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(filePath, optional, optional, optional, optional, optional, optional, optional, optional, optional, optional, optional, optional, optional, optional);
excelWorkbook.CheckCompatibility = false;
excelWorkbook.DoNotPromptForConvert = true;

// Create array with Custom Properties of workbook
dynamic properties = excelWorkbook.CustomDocumentProperties;

// Iterate through each worksheet in the workbook
foreach (Excel.Worksheet excelWorksheet in excelWorkbook.Worksheets)
{
    // Checking to see if any cells are being used. If no cells are used, setting ACTUAL used range causes an error.
    if (excelWorksheet.UsedRange.Cells.Count >=1)
    {
        try
        {
            // Because these sheets have thousands of edited (but unused) cells, can't use UsedRange without major performance issue. Getting last used cell manually.
            int lastRow = 1;
            int lastCol = 1;
            try
            {
                lastRow = excelWorksheet.Cells.Find("*", excelWorksheet.get_Range("IV65536", optional), Excel.XlFindLookIn.xlValues, Excel.XlLookAt.xlPart, Excel.XlSearchOrder.xlByRows, Excel.XlSearchDirection.xlPrevious, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value).Row;
                lastCol = excelWorksheet.Cells.Find("*", excelWorksheet.get_Range("IV65536", optional), Excel.XlFindLookIn.xlValues, Excel.XlLookAt.xlPart, Excel.XlSearchOrder.xlByColumns, Excel.XlSearchDirection.xlPrevious, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value).Column;
            }
            catch { }

            Excel.Range excelRange = excelWorksheet.get_Range(excelWorksheet.Cells[1, 1], excelWorksheet.Cells[lastRow, lastCol]);

            // Creating array of cells in range, because search operations are faster on array than on cells.
            dynamic cells = excelRange.Cells;

            string cellAddress = "";
            string cellFormula = "";
            string formulaParameter = "";
            int parameterLength = 0;

            // Search array for cells that have functions. If a function exists, replace it with the value that should be returned from the function.
            foreach (dynamic c in cells)
            {
                if (c.HasFormula())
                {
                    cellFormula = c.formula;
                    cellAddress = c.address.Replace("$", "");

                    if ((cellFormula.Length > 50) && (cellFormula.Substring(0, 50) == "=YOURCUSTOMEXCELFUNCTIONHERE"))
                    {
                        // Get custom functions, replace functions with the values returned from those functions
                        parameterLength = cellFormula.Substring(52).Length;
                        formulaParameter = cellFormula.Substring(52, parameterLength - 2);

                        foreach (dynamic p in properties)
                        {
                            if (p.name == formulaParameter)
                            {
                                excelWorksheet.get_Range(cellAddress, optional).Value2 = p.Value;
                            }
                        }
                    }
                    else
                    {
                        // Get non-custom functions, replace functions with the values returned from those functions                                                       
                        excelWorksheet.get_Range(cellAddress, optional).Value2 = c.Value2;
                    }
                }
            }
        }
        catch { }
    }
}
answered on Stack Overflow Jul 14, 2014 by Karl • edited Feb 9, 2016 by Adrian773

User contributions licensed under CC BY-SA 3.0