Adding formula to cell Exception from HRESULT: 0x800A03EC - c#

I'm trying to add a formula to cell but i got the error
Exception from HRESULT: 0x800A03EC
There are lots of posts with similar issues however none could help me plus i'm not doing any fancy formula's what i'm doing wrong?
Thread.CurrentThread.CurrentCulture =
new System.Globalization.CultureInfo("en-US");
workbook = application.Workbooks.Open(Helper.GetLocalInstalationFolder() +
#"\IMC.xltx", 0, false, 5, "", "", true, XlPlatform.xlWindows, "\t", false,
false, 0, true, 1, 0);
worksheet = workbook.Worksheets["Report"];
var rowValue = 0;
for (int i = 2; i <= LastRow; i++)
{
rowValue = i - 1;
for (int j = 1; j <= 37; j++)
{
worksheet.Cells[i, j] = MyArray[rowValue, j];
}
// I tried all the following all give the same exception:
worksheet.Range[i, 38].Formula = "=3+4";
worksheet.get_Range("R" + i + "C38").FormulaR1C1 = "=3+4";
worksheet.Range[i, 38].FormulaR1C1 = "=3+4";
worksheet.get_Range("R" + i + "C38").Formula = "=3+4";
}

It is a crappy exception and doesn't mean anything more than you slamming Excel with processing requests at a rate that it cannot keep up with. Your program essentially looks like a hyper-active user that's entering formulas at a rate of one per microsecond.
The workaround is to go slower by intentionally sleeping or to force Excel to do less work. You will very probably fix it in this case by assigning the Application.Calculation property. Set it to manual before you start putting formulas into cells. And back to auto after you're done.
More good advice in this blog post.

Perhaps this brings you into the right direction->
[a link] (http://www.codeproject.com/Questions/470089/Exception-from-HRESULT-0x800A03EC-Error)

in my case I was missing double-quotes in the HYPERLINK formula arguments, i.e. the formula itself was wrong. i tried a valid formula, like ..Cell(x,y).Formula = "=MIN(2)" and it worked, therefore that was the case..

Hans Passant is correct, but there may be additional settings needed to enable Excel's ability to handle the cadence of your code operations.
Here's a good set of options to make Excel capable of processing requests faster: Turn Automatic Calculations Off/On
A summary of what worked for me:
using Excel = Microsoft.Office.Interop.Excel;
public class ExcelAppWrapper : IDisposable
{
private Excel.Application _application;
public ExcelAppWrapper()
{
_application = new Excel.Application { Visible = true };
_application.Workbooks.Add(Missing.Value);
//there must be a workbook before setting Application.Calculation
ConfigureApplication(false);
}
public void Dispose()
{
ConfigureApplication(true);
}
private void ConfigureApplication(bool enable)
{
_application.Calculation = enable ? XlCalculation.xlCalculationAutomatic : XlCalculation.xlCalculationManual;
_application.EnableEvents = enable;
_application.ScreenUpdating = enable;
_application.DisplayStatusBar = enable;
}
}

Related

How to detect that a Paragraph.Range is inside a TOC in a C# Word AddIn

I'm making a MS-Word Addin with some features. One of them is to remove excessive blank lines (the current rule says that the Document can't have more than two sequential blank lines and that it can't have blank lines after the last line of text).
I've made a code to try to achieve this:
private void formatText() {
Microsoft.Office.Interop.Word.Paragraphs paragraphs = Globals.ThisAddIn.Application.ActiveDocument.Paragraphs;
Boolean isPreviousLineEmpty = false;
Boolean isLastLine = true;
for (int i = paragraphs.Count - 1; i > 0; i--) {
Microsoft.Office.Interop.Word.Paragraph paragraph = paragraphs[i];
if (paragraph.Range.Text.Trim().Equals("")) {
if (isLastLine) {
paragraph.Range.Delete();
continue;
}
if (isPreviousLineEmpty) {
paragraph.Range.Delete(); //This is the line where the error happens
}
isPreviousLineEmpty = true;
continue;
}
if (isLastLine) {
paragraph.Range.Text = paragraph.Range.Text.TrimEnd();
isLastLine = false;
}
isPreviousLineEmpty = false;
}
}
It was working untill I've added a "Table of Contents" (TOC) to the document. Now I get an error:
System.Runtime.InteropServices.COMException: 'Cannot edit Range.'
The reason is: there is a white line on the TOC that my code is trying to remove, and it can't. I've searched the documentation/internet and tried everything I could think of to be able to prevent my code from running on TOC lines, but nothing worked.
I need a way to know that I can skip that line, because I don't need to delete blank lines inside TOCs.
For the moment, what I can do is wrap the specific line who executes the deletion with a Try/Catch block, but I don't think this is the best solution (for I may be letting other errors go unnoticed, this is just a silencer).
Does anyone know the correct approach to this case?
UPDATE:
Following Freeflow comment I replaced all my method code with this:
private void formatText() {
Microsoft.Office.Interop.Word.Find find = Globals.ThisAddIn.Application.ActiveDocument.Range().Find;
Microsoft.Office.Interop.Word.Paragraphs paragraphs = Globals.ThisAddIn.Application.ActiveDocument.Paragraphs;
Boolean operationResult = true;
//Remove blank lines at the end of the document
for (int i = paragraphs.Count - 1; i > 0; i--) {
Microsoft.Office.Interop.Word.Paragraph paragraph = paragraphs[i];
if (paragraph.Range.Text.Trim().Equals("")) {
paragraph.Range.Delete();
continue;
}
paragraph.Range.Text = paragraph.Range.Text.TrimEnd();
break;
}
//Remove blank lines between paragraphs
while (operationResult) {
operationResult = find.Execute("^p^p^p", false, false, false, false, false, false, null, null, "^p^p",
Microsoft.Office.Interop.Word.WdReplace.wdReplaceAll);
}
}
It has been working very well untill this moment. If any problem comes up, I'll post here.
Thanks for your comment. If you transform it in an answer I'll mark as the accepted one.
The Word object model has a useful method: InRange, which allows checking whether one range of text is part of another. Logically, then, it's possible to compare whether a paragraph's location is within a TOC.
Below is a test example, originally written in VBA. I'm converting it on-the-fly to C#, so there may be some minor syntax errors...
public void TestRangeInToc()
{
Word.Document doc =Globals.ThisAddIn.Application.ActiveDocument;
bool HasToc = false;
if(doc.TablesOfContents.Count > 0)
{
HasToc = true;
}
foreach(Word.Paragraph para In doc.Paragraphs)
{
if(HasToc)
{
if(IsRangeInTOC(para.Range, doc))
{
Debug.Print("in range");
//skip this one
}
}
}
}
public bool IsRangeInTOC(Word.Range rng, Word.Document doc)
{
Word.TableOfContents toc
foreach(toc in doc.TablesOfContents)
{
if(rng.InRange(toc.Range))
{
return true;
break;
}
}
}

C# COMException reading property of MSWord Shape object Microsoft.Office.Interop.Word

I am trying to loop through all shapes in a document and check their "Alternate Text" which has had the source filename for that image recorded as it's alternate text. I need to read specific source images and convert them to a different image format.
I am able to get to the point of reading the AlternateText of the shape but it throws an exception:
'((Microsoft.Office.Interop.Word.Shape)(s)).AlternativeText' threw an exception of type 'System.Runtime.InteropServices.COMException'
When I set a breakpoint and view the "s" object, the majority of properties are throwing this exception, however some are not, for example I can read the LinkFormat property and a few others without issue, but the majority of properties throw an error.
Here is the code I am using:
Word.Application WordApp = new Word.Application();
d = WordApp.Documents.Open(#strFilename, ReadOnly: true, Visible: false);
int iReplacements = 0;
int iReplacementNoLink = 0;
foreach (Word.Shape s in d.Shapes)
{
Application.DoEvents();
try
{
if (s.LinkFormat.SourceName.ToString().Contains(".eps") || s.LinkFormat.SourceName.ToString().Contains(".png"))
{
iReplacements++;
}
if (s.AlternativeText != "")
{
iReplacementNoLink++;
}
}
catch (Exception fff)
{
Console.Write(fff);
}
}
The if statement checking the s.AlternateText always ends up in the catch.
I am using Visual Studio 2013 and I have Office 2007, I am not sure if that is relevant or not.
Can anyone tell me what I need to do to be able to read the Alternate Text of the shapes? If I am going about it in the wrong way or need to include a library or if I need to upgrade VS or Office? It seems like it should be really straight forward.
Thank you for any assistance you can provide.
I am unsure why this worked, but I was able to resolve this issue by using the "Select" method of the shape. Once the shape is selected the majority of the properties that previously were throwing errors are populated. There are still approximately 20 properties that thow the error, but I am now able to access things like "AlternativeText","Name","Callout" which were previously throwing the error.
Word.Application WordApp = new Word.Application();
d = WordApp.Documents.Open(#strFilename, ReadOnly: true, Visible: false);
int iReplacements = 0;
int iReplacementNoLink = 0;
foreach (Word.Shape s in d.Shapes)
{
Application.DoEvents();
try
{
//if (s.Type == Microsoft.Office.Core.MsoShapeType.msoLinkedPicture)
if (s.LinkFormat.SourceName.ToString().Contains(".eps") || s.LinkFormat.SourceName.ToString().Contains(".png"))
{
iReplacements++;
}
s.Select();
if (s.AlternativeText != "" && s.AlternativeText != null)
{
iReplacementNoLink++;
}
}
catch (Exception fff)
{
Console.Write(fff);
}
}

Formula evaluation not working in NPOI 2.1.3.0

I am creating an Excel workbook in code behind and save it as both XLSX and PDF. I use a template workbook for this that has formatting and formulae to be evaluated after the generating is done. When I open the Excel file, the formulae evaluate only when I set ForceFormulaRecalculation to true. When I do the same with the PDF file, I get #VALUE! where the results should be. My relevant code:
ReportGenerator generator = new ReportGenerator();
List<Activity> activities = GetActivitiesForItemCollection(items);
generator.CreateWorkbook(templatePath);
generator.Year = int.Parse(year);
generator.Month = int.Parse(month);
activities = generator.SortActivitiesByDateTime(activities);
activities = generator.GenerateBreaksForProject(activities);
bool isExternalReport = false;
if (project == "Intern")
isExternalReport = true;
generator.GenerateReports(activities, isExternalReport);
if (pdf && !xlsx)
generator.SaveReportToList(OutputFileType.PDF, generator.AssembleFileName(UserProperties.FullName, project, month, year, OutputFileType.PDF));
else if (xlsx && !pdf)
generator.SaveReportToList(OutputFileType.XLSX, generator.AssembleFileName(UserProperties.FullName, project, month, year, OutputFileType.XLSX));
else
{
generator.SaveReportToList(OutputFileType.XLSX, generator.AssembleFileName(UserProperties.FullName, project, month, year, OutputFileType.XLSX));
generator.SaveReportToList(OutputFileType.PDF, generator.AssembleFileName(UserProperties.FullName, project, month, year, OutputFileType.PDF));
}
Here is my code where I do the evaluation:
public void SaveReportToList(OutputFileType outputType, string filename)
{
string siteUrl = SPContext.Current.Web.Url;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (MemoryStream mStream = new MemoryStream())
{
sheet.PrintSetup.Landscape = true;
sheet.PrintSetup.FitWidth = 1;
sheet.PrintSetup.FitHeight = 1;
XSSFFormulaEvaluator.EvaluateAllFormulaCells(workbook);
workbook.Write(mStream);
using (MemoryStream crutchStream = new MemoryStream(mStream.ToArray()))
{
using (SPSite spsite = new SPSite(siteUrl))
{
using (SPWeb spweb = spsite.OpenWeb())
{
....
I have also tried it this way:
private void ForceCalculateSheet()
{
XSSFFormulaEvaluator helper = (XSSFFormulaEvaluator)workbook.GetCreationHelper().CreateFormulaEvaluator();
for(int i = 0; i<sheet.LastRowNum; i++)
{
XSSFRow row = (XSSFRow)sheet.GetRow(i);
for(int j = 0; j< row.LastCellNum; j++)
{
XSSFCell cell = (XSSFCell)row.GetCell(j);
if(cell != null && cell.CellType == CellType.Formula)
{
helper.EvaluateFormulaCell(cell);
}
}
}
}
Here are a couple of formulae I try to evaluate (some of the cell values are 24-hour time values):
=IF(D37-C37-E37>0;D37-C37-E37;0)
=INT(J39/60)
=J39-C39*60
The weird thing is, when I trace the evaluation in Excel, it goes through until the last step. Then suddenly the value becomes #VALUE!.
Anybody got an idea what's going on here?
Just to be careful, I updated NPOI to it's latest .NET Version (2.1.3.1). This still didn't fix the problem.
When I click a cell that's in the formula, change its value, then confirm it with pressing Enter, the formula evaluates correctly. Meaning there shouldn't be anything wrong with the formulae themselves.
I solved it by manually doing the calculations. This isn't my long-term solution as users should be able to insert their own calculations, but it's the only solution I can come up with right now besides using another Excel framework (bad planning ;)).

using C# to assign a value into Visio's Shape.Text causing exception

doc = app.Documents.Add(fileInfo[i].FullName);
Vis.Shapes shapes = doc.Pages[1].Shapes;
for (int j = 1; j <= shapes.Count; j++)
{
if (shapes[j].Text.StartsWith("getSomeThing"))
{
shapes[j].Text = "doSomething()";
}
}
shapes[j].Text = "doSomething()"; this line will cause an exception, how to fix it?
It causes a COMException.
Exception message is "The requested operation is disabled".
ErrorCode = -2032465766
Maybe there is some shape with lock on text edit. You can remove that protection:
shape.get_CellsSRC((short)VisSectionIndices.visSectionObject,
(short)VisRowIndice‌​s.visRowLock,
(short)VisCellIndices.visLockTextEdit).FormulaU = "0"; //to remove protection
And it is better to "remember" old value and set it back after yours edits.

C# Downloadable Excel Files from Class Library

I'm looking for some advice. I'm building on an additional feature to a C# project that someone else wrote. The solution of the project consists of an MVC web application, with a few class libraries.
What I'm editing is the sales reporting function. In the original build, a summary of the sales reports were generated on the web application. When the user generates the sales report, a Reporting class is called in one of the C# class libraries. I'm trying to make the sales reports downloadable in an excel file when the user selects a radio button.
Here is a snippet of code from the Reporting class:
public AdminSalesReport GetCompleteAdminSalesReport(AdminSalesReportRequest reportRequest)
{
AdminSalesReport report = new AdminSalesReport();
string dateRange = null;
List<ProductSale> productSales = GetFilteredListOfAdminProductSales(reportRequest, out dateRange);
report.DateRange = dateRange;
if (titleSales.Count > 0)
{
report.HasData = true;
report.Total = GetTotalAdminSales(productSales);
if (reportRequest.Type == AdminSalesReportRequest.AdminSalesReportType.Complete)
{
report.ProductSales = GetAdminProductSales(productSales);
report.CustomerSales = GetAdminCustomerSales(productSales);
report.ManufacturerSales = GetAdminManufacturerSales(productSales);
if (reportRequest.Download)
{
FileResult ExcelDownload = GetExcelDownload(productSales);
}
}
}
return report;
}
So as you can see, if reportRequest.Download == true, the class should start up the process of creating the excel file. All the GetAdminSales functions do it use linq queries to sort out the sales if they are being displayed on the webpage.
So I have added this along with the GetAdminSales functions:
private FileResult GetExcelDownload(List<TitleSale> titleSales)
{
CustomisedSalesReport CustSalesRep = new CustomisedSalesReport();
Stream SalesReport = CustSalesRep.GenerateCustomisedSalesStream(productSales);
return new FileStreamResult(SalesReport, "application/ms-excel")
{
FileDownloadName = "SalesReport" + DateTime.Now.ToString("MMMM d, yyy") + ".xls"
};
}
and to format the excel sheet, I'm using the NPOI library, and my formatter class is laid out like so:
public class CustomisedSalesReport
{
public Stream GenerateCustomisedSalesStream(List<ProductSale> productSales)
{
return GenerateCustomisedSalesFile(productSales);
}
private Stream GenerateCustomisedSalesFile(List<ProductSale> productSales)
{
MemoryStream ms = new MemoryStream();
HSSFWorkbook templateWorkbook = new HSSFWorkbook();
HSSFSheet sheet = templateWorkbook.CreateSheet("Sales Report");
HSSFRow dataRow = sheet.CreateRow(0);
HSSFCell cell = dataRow.CreateCell(0);
cell = dataRow.CreateCell(0);
cell.SetCellValue(DateTime.Now.ToString("MMMM yyyy") + " Sales Report");
dataRow = sheet.CreateRow(2);
string[] colHeaders = new string[] {
"Product Code",
"Product Name",
"Qty Sold",
"Earnings",
};
int colPosition = 0;
foreach (string colHeader in colHeaders)
{
cell = dataRow.CreateCell(colPosition++);
cell.SetCellValue(colHeader);
}
int row = 4;
var adminTotalSales = GetAdminProductSales(productSales);
foreach (SummaryAdminProductSale t in adminTotalSales)
{
dataRow = sheet.CreateRow(row++);
colPosition = 0;
cell = dataRow.CreateCell(colPosition++);
cell.SetCellValue(t.ProductCode);
cell = dataRow.CreateCell(colPosition++);
cell.SetCellValue(t.ProductName);
cell = dataRow.CreateCell(colPosition++);
cell.SetCellValue(t.QtySold);
cell = dataRow.CreateCell(colPosition++);
cell.SetCellValue(t.Total.ToString("0.00"));
}
}
templateWorkbook.Write(ms);
ms.Position = 0;
return ms;
}
Again like before, the GetAdminSales (GetAdminProductSales, etc) are contained in the bottom of the class, and are just linq queries to gather the data.
So when I run this, I don't get any obvious errors. The summary sales report appears on screen as normal but no excel document downloads. What I have done, which may be putting this off is in my class library I have referened the System.Web.Mvc dll in order to download the file (I have not done it any other way before - and after reading up on the net I got the impression I could use it in a class library).
When I debug through the code to get a closer picture of what's going on, everything seems to be working ok, all the right data is being captured but I found that from the very start - the MemoryStream ms = new Memory Stream declaration line in my formatter class shows up this (very hidden mind you) :
ReadTimeout '((System.IO.Stream)(ms)).ReadTimeout'
threw an exception of type
'System.InvalidOperationException' int
{System.InvalidOperationException}
+{"Timeouts are not supported on this stream."} System.SystemException
{System.InvalidOperationException}
I get the same for 'WriteTimeout'...
Apologies for the long windedness of the explaination. I'd appreciate it if anyone could point me in the right direction, either to solve my current issue, or an alternative way of making this work.
Without getting bogged down in the details, the obvious error is that in GenerateCustomisedSalesFile you create a MemoryStream ms, do nothing with it, then return it.

Categories

Resources