Excel Automation From .NET - creating a new worksheet - c#

I am attempting what seems like a simple task: using C# to create a new Excel document containing new worksheets.
For some reason, I am getting a strange COM error (0x800A03EC)
Has anyone managed to get this to work? Does anyone have suggestions as to how to troubleshoot this?
I've isolated this into the minimum amount of code:
using Microsoft.Office.Interop.Excel;
using System.Diagnostics;
namespace ExcelAutomation
{
public static class ExcelTests
{
public static void CreateWorksheet()
{
try
{
var app = new Microsoft.Office.Interop.Excel.Application();
app.Visible = true;
var workBooks = app.Workbooks;
var newWorkbook = app.Workbooks.Add(XlWBATemplate.xlWBATWorksheet);
Worksheet existingWorksheet = (Worksheet)newWorkbook.Sheets[1];
Worksheet workSheet = (Worksheet)newWorkbook.Sheets.Add
(
null, // before
existingWorksheet,
null, // 1,
null //XlSheetType.xlWorksheet
);
}
catch (System.Runtime.InteropServices.COMException ex)
{
Trace.WriteLine(string.Format("Caught COMException. Message: \"{0}\"", ex.Message));
}
}
}
}
The output window now says:
Caught COMException. Message: "Exception from HRESULT: 0x800A03EC"

The mistake I'm making is to use null for optional values that I don't want to set.
Instead I should use System.Reflection.Missing.Value
Worksheet workSheet = (Worksheet)newWorkbook.Sheets.Add
(
existingWorksheet, // before
System.Reflection.Missing.Value,
System.Reflection.Missing.Value, // 1,
System.Reflection.Missing.Value //XlSheetType.xlWorksheet
);

I Think this will help you
Visit http://www.aspose.com/docs/display/cellsnet/Adding+New+Worksheets+to+Workbook+and+Activating+a+Sheet

Related

How to copy data from c# winform and paste into Excel Worksheet

I'm working on a program that allows the user to pull up part numbers from a database. The part numbers are then to be pasted into an active Excel Sheet.
I'm trying to do this with Excel interop Excel 16.0. I can copy the data but am having issues getting it to paste into excel.
private void cmdCopyToExcel_Click(object sender, EventArgs e)
{
string wb = cmb_BookName.Text.ToString();
string ws = cmb_SheetName.Text.ToString();
if (chkContainer.Checked)
{
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkbook = xlApp.Workbooks[wb];
Excel.Worksheet xlWorksheet = xlWorkbook.Sheets[ws];
xlWorksheet.Cells[48, 4] = cboContainer.Text;
}
I'm able to get the open excel workbook and worksheet that I need, but when I try to paste it into excel all I get is a COM Exception. The exception occurs on line 10. I've tried using ("wb name") and ("ws name"), have also tried using index numbers [1] for workbook and [3] for worksheets but nothing works.
Can anyone see what I'm doing wrong or is there an easier way to copy from C# and paste into an excel cell?
Addition:I tried opening the workbook that I wanted to add test to, just to see if I could get it to work.
Here is the code:
private void button1_Click(object sender, EventArgs e)
{
try
{
//create a instance for the Excel object
Excel.Application oExcel = new Excel.Application();
//specify the file name where its actually exist
string filepath = #"K:\R&D Dept\Development Lab\R&D Test Request System (For testing and training)\Test Matrices\JRD Test Matrix for part numbers.xlsm";
//pass that to workbook object
Excel.Workbook WB = oExcel.Workbooks.Open(filepath);
// statement get the workbookname
string ExcelWorkbookname = WB.Name;
// statement get the worksheet count
int worksheetcount = WB.Worksheets.Count;
Excel.Worksheet wks = (Excel.Worksheet)WB.Worksheets[3];
// statement get the firstworksheetname
string firstworksheetname = wks.Name;
//statement get the first cell value
var firstcellvalue = ((Excel.Range)wks.Cells[48, 4]).Value;
}
catch (Exception ex)
{
string error = ex.Message;
}
}
}
}
This worked, so I guess my question becomes how to work with an Excel workbook and worksheet that are already open?
I would start by getting a range of cells: i.e.{Range test = {yourWorksheet}.Cells[RowNumber, ColumnNumber]}
Once you have that, you can set the value of that cell by calling the value, or value2 property like so: {test.Value or test.Value2 = {yourPastedData}}

C#: Microsoft.Interop.Excel Refresh all not working

I have a really frustrating issue where whenever I call
RefreshAll() from Microsoft.Interop.Excel it does not refresh the data when I open the workbook in excel and I have to manually click the refresh all button within excel... I have even tried calling refresh all via vba and it still does not refresh the data... I am always prompted with:
"The PivotTable report was saved without underlying data. Use the
Refresh Data command to update the report."
Despite the fact that I already called the "Refresh all command."
public void applyMacro(string excelFile)
{
var excelApplication = new Microsoft.Office.Interop.Excel.Application { Visible = false };
var targetExcelFile = excelApplication.Workbooks.Open(excelFile);
try
{
string[] macros = addMacros(ref targetExcelFile);
for (int i = 0; i < 2; i++)
excelApplication.Run(macros[i]);
targetExcelFile.RefreshAll();
targetExcelFile.Save();
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadKey();
}
finally
{
excelApplication.Quit();
}
}
and in vba have tried adding the following before calling the refresh:
For Each ws In Worksheets
For Each qt In ws.QueryTables
qt.Refresh BackGroundQuery:=False
next qt
Next ws
Any ideas??
You can use this on your pivot table :
YourPivotTable.PivotCache().RefreshOnFileOpen = true;
YourPivotTable.SaveData = true;

Excel interop doesn't accept ranges with commas

According to the documentation of Workbook.Range, you can provide commas in the first argument to provide an union.
However, the following code throws a COMException with HRESULT 0x800A03EC on the line that gets the range:
using Microsoft.Office.Interop.Excel;
public void RangeWithCommas() {
var excel = new Application();
var wb = excel.Workbooks.Add(xlWBATemplate.xlWBATWorksheet);
var ws = (Worksheet)wb.Worksheets[1];
var range = ws.Range["A1,A2"]; // this throws an exception
Console.WriteLine(range.Address[false,false]);
ws.Delete();
wb.Close(false);
excel.Quit();
}
How can I do or fix this?
P.S. I am aware of Application.Union but I would very much prefer not to use it because there is no easy way to provide a variable number of arguments.
As AnalystCave.com pointed out, some Excel COM methods are locale specific. You need to use the regional list seperator when accessing the COM method.
This code should work correctly on all locales:
using Microsoft.Office.Interop.Excel;
public void RangeWithCommas() {
var excel = new Application();
var wb = excel.Workbooks.Add(xlWBATemplate.xlWBATWorksheet);
var ws = (Worksheet)wb.Worksheets[1];
var rangestring = String.Join((string)excel.International[XlApplicationInternational.xlListSeparator], new [] {"A1","A2"});
var range = ws.Range[rangestring];
Console.WriteLine(range.Address[false,false]);
ws.Delete();
wb.Close(false);
excel.Quit();
}

How to get CustomDocumentProperties using Excel Interop?

The below code is used to get the custom document properties for Excel workbook.
var xlApp = Globals.ThisAddIn.Application; // This works in VSTO Excel Add-in
var xlApp = new global::Microsoft.Office.Interop.Excel.Application(); // This doesn't work anywhere
xlApp.Visible = true;
global::Microsoft.Office.Interop.Excel.Workbook workbook = xlApp.Workbooks.Open(file, false, true, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, false, Type.Missing, Type.Missing);
global::Microsoft.Office.Core.DocumentProperties properties = workbook.CustomDocumentProperties; // Exception occurs here
global::Microsoft.Office.Core.DocumentProperty property = properties["propertyname"];
The first 2 lines are references to the Excel Application. One obtain the reference from VSTO add-in internals, the other is a regular new Application().
When using the Application from VSTO internals, the code run fines without any problems. But when using new Application(), the workbook.CustomDocumentProperties line throws InvalidCastException:
Unable to cast COM object of type 'System.__ComObject' to interface
type 'Microsoft.Office.Core.DocumentProperties'. This operation failed
because the QueryInterface call on the COM component for the interface
with IID '{2DF8D04D-5BFA-101B-BDE5-00AA0044DE52}' failed due to the
following error: No such interface supported (Exception from HRESULT:
0x80004002 (E_NOINTERFACE)).
I am trying to make it to work on a C# winforms project without VSTO. A lot of examples and tutorials use new Application() for Excel interop, but I noticed that Microsoft.Office.Interop.Excel.Application is an interface, so using new on interface is actually strange to me. How can I create a proper Application that can get the CustomDocumentProperties?
Reference Assemblies I am using:
Microsoft.Office.Interop.Excel v2.0.50727 Version 14.0.0.0
Microsoft.CSharp v4.0.30319 Version 4.0.0.0
I noticed that Microsoft.Office.Interop.Excel.Application is an interface, so using new on interface is actually strange to me.
That is strange indeed, but by design. The Excel.Application interface is decorated with the CoClass attribute telling the actual class to instantiate on 'instantiating' the interface. More about it here.
But when using new Application(), the workbook.CustomDocumentProperties line throws InvalidCastException:
Strange indeed again. I have experienced some issues myself using document properties. It seems that the actual class returned differs from the spec, so I moved to use dynamic in order to prevent type casting issues.
So instead of this:
Microsoft.Office.Core.DocumentProperties properties = workbook.CustomDocumentProperties;
Use:
dynamic properties = workbook.CustomDocumentProperties;
How can I create a proper Application that can get the CustomDocumentProperties?
There is no need to create a new Excel Application instance if you develop an add-in. You should use the Application property provided by the VSTO runtime:
var xlApp = Globals.ThisAddIn.Application; // This works in VSTO Excel Add-in
But if you develop a standalone application which automates Excel, in that case you need to create a new Application instance by using the new operator:
var xlApp = new global::Microsoft.Office.Interop.Excel.Application();
Use the late binding technology (Type.InvokeMember) for getting or setting document property as the How To Use Automation to Get and to Set Office Document Properties with Visual C# .NET article suggests.
I've had a same problem. Today it has been resolved. There is a different approach to derive the results. The question and its' answer is at
How can I read excel custom document property using c# excel interop
Here is my implementation.
public string CheckDocProp(string propName, object props)
{
Excel.Workbook workBk = Globals.ThisAddIn.Application.ActiveWorkbook;
object customProperties = workBk.CustomDocumentProperties;
Type docPropsType = customProperties.GetType();
object nrProps;
object itemProp = null;
object oPropName;
object oPropVal = null;
nrProps = docPropsType.InvokeMember("Count",
BindingFlags.GetProperty | BindingFlags.Default,
null, props, new object[] { });
int iProps = (int)nrProps;
for (int counter = 1; counter <= ((int)nrProps); counter++)
{
itemProp = docPropsType.InvokeMember("Item",
BindingFlags.GetProperty | BindingFlags.Default,
null, props, new object[] { counter });
oPropName = docPropsType.InvokeMember("Name",
BindingFlags.GetProperty | BindingFlags.Default,
null, itemProp, new object[] { });
if (propName == oPropName.ToString())
{
oPropVal = docPropsType.InvokeMember("Value",
BindingFlags.GetProperty | BindingFlags.Default,
null, itemProp, new object[] { });
return oPropVal.ToString();
break;
}
else
{
return "Not Found.";
}
}
return "Not Found.";
}
Usage:
object docProps = wb.CustomDocumentProperties;
string prop1 = ExistsDocProp("<CustomProperty>", docProps);

Handling "No cells were found." Error in Excel

I am working on Excel VSTO application and finding error cells in the worksheets using the below code
Excel.Range rngTemp;
Excel.Range rngErrorRange;
Excel._Worksheet Sheet1 = (Excel._Worksheet)xlCTA.Sheets["Sheet1"];
rngTemp = wsCTAWK11.UsedRange;
rngErrorRange = rngTemp.SpecialCells(Excel.XlCellType.xlCellTypeFormulas, Excel.XlSpecialCellsValue.xlErrors);
when there are really error cells found then i do not have any issues but when i dont have any error cells in these sheet i get the below exception
**threw an exception of type 'System.Runtime.InteropServices.COMException'
base {System.Runtime.InteropServices.ExternalException}: {"No cells were found."}**
How to handle this... Pls help
Catch the exception and handle it however you wish?
try
{
Excel.Range rngTemp;
Excel.Range rngErrorRange;
Excel._Worksheet Sheet1 = (Excel._Worksheet)xlCTA.Sheets["Sheet1"];
rngTemp = wsCTAWK11.UsedRange;
rngErrorRange = rngTemp.SpecialCells(Excel.XlCellType.xlCellTypeFormulas,
Excel.XlSpecialCellsValue.xlErrors);
}
catch (System.Runtime.InteropServices.COMException ex)
{
//Handle here
}
Instead of using the built in SpecialCells method write your own extension method that wraps the call to myRange.SpecialCells with error handling.
I did the following:
public static Range SpecialCellsCatchError(this Range myRange, XlCellType cellType)
{
try
{
return myRange.SpecialCells(cellType);
}
catch (System.Runtime.InteropServices.COMException ex)
{
return null;
}
}
Then you will have to account for null but it won't throw an error.

Categories