Excel Interop 0×80010105 - c#

I created a tool to convert Excel files. When the user convert a excel file the code create a Excel file first. When I'm on my system (Excel 2007) it's working without problems. When I install the program on a system with Excel 98 then it's throwing an exception. The first exception I got was another one, but also a HResult error. I fixed this through change the "SaveAs" to "SaveCopyAs". Then it was FIXED! Also for the other systems where Excel 98 is installed, but now I have another HResult error. What is the problem here:
_savePath = sfd.FileName;
MessageBox.Show("GOOD1");
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
MessageBox.Show("GOOD2");
// The exception is here on the workbook
// HResult 8x00010105 (COMException)
Microsoft.Office.Interop.Excel.Workbook workbook = excelApp.Workbooks.Add(Missing.Value);
MessageBox.Show("GOOD3");
workbook.SaveCopyAs(_savePath);
MessageBox.Show("GOOD4");
lblSavePath.Text = _savePath;
workbook.Close(false, _savePath, Type.Missing);
excelApp.Quit();
I hope someone could help me with this problem.
Thanks,
Jamie

You might try:
_savePath = sfd.FileName;
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
MessageBox.Show("GOOD2");
excelApp.SheetsInNewWorkbook = 1;
try
{
// Must be surrounded by try catch to work.
excelApp.Visible = true;
}
catch (Exception e)
{
Console.WriteLine("-------Error hiding the application-------");
Console.WriteLine("Occured error might be: " + e.StackTrace);
}
Microsoft.Office.Interop.Excel.Workbook workbook
workbook = excelApp.Workbooks.Open("your excel file", Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); // if working with another excel
excelApp.Workbooks.Add();
MessageBox.Show("GOOD3");
Excel.Worksheet sheetC = excelApp.Sheets.get_Item(1);
sheetC.Name = "name-of-sheet";
workbook.SaveCopyAs(_savePath); // SaveAs should work actually.
workbook.Close();
excelApp.Quit();
I took your solution and modified the Missing.Value part which wasn't correct. Plus you don't really need to give parameters to the workbook.Close.
Solution found here: I want to add only one sheet after creating an Excel workbook through C#

Maybe try your code without the excelApp.Quit(); line.
Use the excelApp.Quit(); function only if you are not going to use the excelApp object again.

Related

Excel interop workbook.SaveAs() removes original formatting?

How can I preserve a worksheet's formatting when using Microsoft.Office.Interop.Excel.Workbook.SaveAs(...)?
For example, I open a previously created workbook with Excel 2010 and I see that it looks beautiful: bold fonts in column headers, nice grid lines, good highlight colors showing input cells, etc.
The I switch to VS2012 and using the ExcelAppManager I wrote below I start by opening the workbook that has the beautiful formatting. I then use the Interop library to write new cell values, programmatically, to one of the worksheets. I then save the worksheet using SaveAs(), as shown below in the ExcelAppManager. I then open the worksheet using Microsoft Excel 2010: I can see the values I wrote in the respective cells - which is great, it worked - but the entire workbook no longer has formatting. It's plain vanilla formatting and all the beautiful format is gone.
I define formatting as anything that format painter would operate on: bold, font, alignment, grid lines, indents, widths and heights, etc.
Sample code:
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;
namespace ExcelStuff
{
public class ExcelAppManager
{
private Application _excelApp;
private bool _isDefaultWorksheets = true;
private Workbook _workBook;
private Workbooks _workBooks;
private Sheets _workSheets;
public ExcelAppManager(string pathToExistingWorksheet)
{
_excelApp = new Application {DisplayAlerts = false};
_workBooks = _excelApp.Workbooks;
_workBook = _workBooks.Open(pathToExistingWorksheet, Type.Missing, false, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
_workSheets = _workBook.Worksheets;
// NOTE: following lines are nice for debug of existing worksheets (to find the worksheets names)
//Get the reference of second worksheet
// var worksheet = (Microsoft.Office.Interop.Excel.ExcelWorksheet) _workSheets.Item[1];
// string strWorksheetName = worksheet.Name; //Get the name of worksheet.
_isDefaultWorksheets = true;
}
public ExcelAppManager()
{
}
public void Initialize()
{
_excelApp = new Application {DisplayAlerts = false};
_workBooks = _excelApp.Workbooks;
_workBook = _workBooks.Add(Missing.Value);
_workSheets = _workBook.Worksheets;
_isDefaultWorksheets = true;
}
public void KillProcess()
{
_workBook.Close();
_workBooks.Close();
_excelApp.Quit();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
Marshal.FinalReleaseComObject(_workSheets);
Marshal.FinalReleaseComObject(_workBook);
Marshal.FinalReleaseComObject(_workBooks);
Marshal.FinalReleaseComObject(_excelApp);
}
public void SaveAs(string filepath, string fileExtensionOfExcelFile)
{
_excelApp.DisplayAlerts = false;
if (fileExtensionOfExcelFile == "xlsm")
{
_workBook.SaveAs(filepath, XlFileFormat.xlOpenXMLWorkbookMacroEnabled,
Type.Missing, Type.Missing, true, false, XlSaveAsAccessMode.xlNoChange,
XlSaveConflictResolution.xlLocalSessionChanges, Type.Missing, Type.Missing);
}
else
{
_workBook.SaveAs(filepath, Type.Missing,
Type.Missing, Type.Missing, true, false, XlSaveAsAccessMode.xlNoChange,
XlSaveConflictResolution.xlLocalSessionChanges, Type.Missing, Type.Missing);
}
}
internal Sheets GetSheets()
{
return _workSheets;
}
}
And in my client code, I use the ExcelAppManager like this:
var _manager = new ExcelAppManager(_excelFilepath);
When you use Interop library in VS2012 it use Office 2013 by default and your saving the workbook in that format. And later you are opening it up with Office 2010. This may be the reason for the Original format loss. Try to save the excel workbook in 2010 format this might resolve the issue.

C# Com OLE Server

I am trying to figure out the best way to interact with an OLE Server using C# .NET
i have found some code that enables interaction with COM+ that appears to work for the OLE server but I wonder if there is a more elegant or simpler way?
I require that it be late bound.
Code (as pilfered from elsewhere on the net)
// Code start
Type excel;
object[] parameter = new object[1];
object excelObject;
try
{
//Get the excel object
excel = Type.GetTypeFromProgID("Excel.Application");
//Create instance of excel
excelObject = Activator.CreateInstance(excel);
//Set the parameter whic u want to set
parameter[0] = true;
//Set the Visible property
excel.InvokeMember("Visible", BindingFlags.SetProperty, null, excelObject, parameter);
Obviously in my case I am putting the name of my ole server in where Excel.Application is, but I have seen cases in EARLY binding where you can call the function directly off the object without having to go via 'InvokeMember'
Is this possible? Can I use Type to cast as object as my type?
Thanks.
If you are using .NET 4.0 you can use dynamic instead of object and invoke the members as if they were there. This will then be checked at runtime, and if the name is correct, execute it.
//Get the excel object
var excel = Type.GetTypeFromProgID("Excel.Application");
//Create instance of excel
dynamic excelObject = Activator.CreateInstance(excel);
excelObject.Visible = true;
Try having a look at this from the add references. It gives you useful access to Excel.
Microsoft.Office.Core
Microsoft.Office.Interop.Excel
using Excel = Microsoft.Office.Interop.Excel;
...
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
Excel.Application app;
Excel.Workbook workbook;
app = new Excel.ApplicationClass();
app.AutomationSecurity = Microsoft.Office.Core.MsoAutomationSecurity.msoAutomationSecurityForceDisable;
workbook = app.Workbooks.Open( openFileDialog.FileName,
0,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing);
return workbook;
}
Cells and worksheets etc can be accessed like this:
Excel.Worksheet worksheet = (Excel.Worksheet)workbook.Worksheets.Item[1];
worksheet.Cells.Item[6, 1]).Value;

How do I Change the Sheet Name from C# on an Excel Spreadsheet

I have a C# application where I am creating numerous Excel Files from Data in a Database. This part is working fine. However, my user asked if the sheet tab could be modified to reflect a field from the database. This sounds simple, however, when I try to reset the name, it tells me that it is read only and cannot be set. I have tried the following and it has not worked:
xlApp.Sheets[0].Range["A1"].Value = "NewTabName";
ALSO TRIED:
xlApp.Name = "NewTabName";
I did a google search and saw some other approaches which did not work for me as well. And a few responses indicated that it is readonly and could not be done.
This seems like something that should be simple. How can I do it.
You need to get access to the actual worksheet. Try something like:
Microsoft.Office.Interop.Excel.Worksheet worksheet = (Worksheet)xlApp.Worksheets["Sheet1"];
worksheet.Name = “NewTabName”;
Here is a fairly complete example I am copying in from existing code.
Works perfectly on Windows 10 with Excel from Office 365
Ensure you add a reference to -
Microsoft.Office.Interop.Excel
My path for this DLL (may differ depending on office version) -
C:\WINDOWS\assembly\GAC_MSIL\Microsoft.Office.Interop.Excel\15.0.0.0__71e9bce111e9429c\Microsoft.Office.Interop.Excel.dll
// Add this at top of C# file -
using Excel = Microsoft.Office.Interop.Excel;
// In your class or function -
private static Excel.Application XlApp = null;
private static Excel.Workbook XlWorkbook = null;
// In your function -
XlApp = new Excel.ApplicationClass();
// Load workbook
XlWorkbook = XlApp.Workbooks.Open(#"Filename.xls",
0, false, Type.Missing, "", "", true, Excel.XlPlatform.xlWindows,
Type.Missing, Type.Missing, Type.Missing,
Type.Missing, true, Type.Missing,
Type.Missing);
// Get reference to sheet
XlWorksheet = (Excel.Worksheet)XlWorkbook.Worksheets["Sheet1"];
int numsheets = XlWorkbook.Sheets.Count;
// iterates through all sheets (1-n inclusive, not zero based)
for(int i=1;i<=numsheets;i++)
{
Excel.Worksheet sht = (Excel.Worksheet)XlWorkbook.Worksheets[i];
// Show sheet name
Console.WriteLine(i+" "+sht.Name);
}
// To save with a same or different filename
XlWorkbook.SaveAs(#"Filename.xls",
Excel.XlFileFormat.xlWorkbookNormal, "",
"", false, false,
Excel.XlSaveAsAccessMode.xlNoChange, Type.Missing,
true, Type.Missing, Type.Missing, Type.Missing);
// Close Excel
XlWorkbook.Close(true, Type.Missing, Type.Missing);
XlApp.Quit();
// Ensure you release resources
releaseObject(XlApp);
releaseObject(XlWorkbook);
releaseObject(XlWorksheet);
Separate function called from above
private static void releaseObject(object obj)
{
// try .. catch
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
}

how to check Excel Workbook or sheet is password protected or not?

using vsto, C# fx 3.5,
how to check Excel Workbook or sheet is password protected or not?
You can check if a workbook is password protected via the Workbook.HasPassword property. You can set the workbook password via the Workbook.SaveAs method:
Excel.Workbook myWorkbook = ...;
if (!myWorkbook.HasPassword)
{
excelWorkbook.Application.DisplayAlerts = false;
excelWorkbook.SaveAs(
excelWorkbook.Name,
Type.Missing,
"My Password",
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing);
}
A worksheet can have it's cell contents protected, the drawing objects protected, and/or the scenarios protected. These can be checked via the Worksheet.ProtectContents, Worksheet.ProtectDrawingObjects, and Worsksheet.ProtectScenarios properties, respectively. I do not know of any way of testing if the worksheet is protected with a password or not, other than trying to call Worksheet.Unprotect, passing in an empty string for the password, and then seeing if the worksheet was successfully unprotected:
bool wasPasswordProtected;
try
{
myWorksheet.Unprotect(string.Empty);
// Unprotect suceeded:
wasPasswordProtected = false;
}
catch
{
// Unprotect failed:
wasPasswordProtected = true;
}
You can set the protection setting for the worksheet via the Worksheet.Protect method. The following example will protect the worksheet if any of the three protection elements are not set. It also sets a password and passes in the 'UserInterfaceOnly' argument as 'true', which means that only the user is blocked from editing the worksheet, while code such as VBA, VB.NET, or C# would not be prevented from manipulating the worksheet. Setting 'UserInterfaceOnly' to 'false' would lock out all changes, whether made by the user or via code.
if(!myWorksheet.ProtectContents ||
!myWorksheet.ProtectDrawinngObjects ||
!myWorsksheet.ProtectScenarios)
{
string myPassword = "...";
bool protectContents = true;
bool protectDrawingObjects = true;
bool protectScenarios = true;
bool userInterfaceOnly = true;
myWorksheet.Protect(
myPassword,
protectDrawingObjects,
protectContents,
protectScenarios,
userInterfaceOnly,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing,
Type.Missing);
Note that the 'UserInterfaceOnly' does NOT persist when the workbook is saved and reverts to 'false' automatically when the workbook is closed. If you wish it to be 'true' in all future sessions as well, the 'UserInterfaceOnly' setting must be re-applied by calling the 'Worksheet.Protect' method each time the workbook is open. This can be be done by subscribing to the Workbook.Open event.
You also might want to read the help files regarding the Worksheet.Protect method so you can understand the optional parameters, paying particular attention to the 'UserInterfaceOnly' parameter.
Check the HasPassword property.
If you want to check if an excel workbook is password protected checking the HasPassword property on a workbook object will not work, because you must open a workbook before you can check the properties, and you can't open a workbook that is password protected if you don't have the password. See the problem?
This is the solution I found to know if the workbook has a password or not:
using Excel = Microsoft.Office.Interop.Excel;
Excel.Application xlsApp = new Excel.Application();
xlsApp.DisplayAlerts = false;
Excel.Workbooks wkbs = xlsApp.Workbooks;
Excel.Workbook wkb;
try
{
wkb = wkbs.Open(path, ReadOnly: true, Password: "");
//If you don't send a string for the password, it will popup a window
//asking for the password and halt your program. If the workbook has no
//password, it will open just fine.
}
catch (Exception ex)
{
//If the file is password protected or otherwise unreadable, it will throw an exception.
}
wkb.Close(false);
xlsApp.Quit();

C# - How to add an Excel Worksheet programmatically - Office XP / 2003

I am just starting to fiddle with Excel via C# to be able to automate the creation, and addition to an Excel file.
I can open the file and update its data and move through the existing worksheets. My problem is how can I add new sheets?
I tried:
Excel.Worksheet newWorksheet;
newWorksheet = (Excel.Worksheet)excelApp.ThisWorkbook.Worksheets.Add(
Type.Missing, Type.Missing, Type.Missing, Type.Missing);
But I get below COM Exception and my googling has not given me any answer.
Exception from HRESULT: 0x800A03EC Source is: "Interop.Excel"
I am hoping someone maybe able to put me out of my misery.
You need to add a COM reference in your project to the "Microsoft Excel 11.0 Object Library" - or whatever version is appropriate.
This code works for me:
private void AddWorksheetToExcelWorkbook(string fullFilename,string worksheetName)
{
Microsoft.Office.Interop.Excel.Application xlApp = null;
Workbook xlWorkbook = null;
Sheets xlSheets = null;
Worksheet xlNewSheet = null;
try {
xlApp = new Microsoft.Office.Interop.Excel.Application();
if (xlApp == null)
return;
// Uncomment the line below if you want to see what's happening in Excel
// xlApp.Visible = true;
xlWorkbook = xlApp.Workbooks.Open(fullFilename, 0, false, 5, "", "",
false, XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
xlSheets = xlWorkbook.Sheets as Sheets;
// The first argument below inserts the new worksheet as the first one
xlNewSheet = (Worksheet)xlSheets.Add(xlSheets[1], Type.Missing, Type.Missing, Type.Missing);
xlNewSheet.Name = worksheetName;
xlWorkbook.Save();
xlWorkbook.Close(Type.Missing,Type.Missing,Type.Missing);
xlApp.Quit();
}
finally {
Marshal.ReleaseComObject(xlNewSheet);
Marshal.ReleaseComObject(xlSheets);
Marshal.ReleaseComObject(xlWorkbook);
Marshal.ReleaseComObject(xlApp);
xlApp = null;
}
}
Note that you want to be very careful about properly cleaning up and releasing your COM object references. Included in that StackOverflow question is a useful rule of thumb: "Never use 2 dots with COM objects". In your code; you're going to have real trouble with that. My demo code above does NOT properly clean up the Excel app, but it's a start!
Some other links that I found useful when looking into this question:
Opening and Navigating Excel with C#
How to: Use COM Interop to Create an Excel Spreadsheet (C# Programming Guide)
How to: Add New Worksheets to Workbooks
According to MSDN
To use COM interop, you must have
administrator or Power User security
permissions.
Hope that helps.
Would like to thank you for some excellent replies. #AR., your a star and it works perfectly. I had noticed last night that the Excel.exe was not closing; so I did some research and found out about how to release the COM objects. Here is my final code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;
using Excel;
namespace testExcelconsoleApp
{
class Program
{
private String fileLoc = #"C:\temp\test.xls";
static void Main(string[] args)
{
Program p = new Program();
p.createExcel();
}
private void createExcel()
{
Excel.Application excelApp = null;
Excel.Workbook workbook = null;
Excel.Sheets sheets = null;
Excel.Worksheet newSheet = null;
try
{
FileInfo file = new FileInfo(fileLoc);
if (file.Exists)
{
excelApp = new Excel.Application();
workbook = excelApp.Workbooks.Open(fileLoc, 0, false, 5, "", "",
false, XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
sheets = workbook.Sheets;
//check columns exist
foreach (Excel.Worksheet sheet in sheets)
{
Console.WriteLine(sheet.Name);
sheet.Select(Type.Missing);
System.Runtime.InteropServices.Marshal.ReleaseComObject(sheet);
}
newSheet = (Worksheet)sheets.Add(sheets[1], Type.Missing, Type.Missing, Type.Missing);
newSheet.Name = "My New Sheet";
newSheet.Cells[1, 1] = "BOO!";
workbook.Save();
workbook.Close(null, null, null);
excelApp.Quit();
}
}
finally
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(newSheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets);
System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp);
newSheet = null;
sheets = null;
workbook = null;
excelApp = null;
GC.Collect();
}
}
}
}
Thank you for all your help.
Another "Up Tick" for AR..., but if you don't have to use interop I would avoid it altogether. This product is actually quite interesting:
http://www.clearoffice.com/ and it provides a very intuitive, fully managed, api for manipulation excel files and seems to be free. (at least for the time being) SpreadSheetGear is also excellent but pricey.
my two cents.
Do not forget to include Reference to Microsoft Excel 12.0/11.0 object Library
using Excel = Microsoft.Office.Interop.Excel;
// Include this Namespace
Microsoft.Office.Interop.Excel.Application xlApp = null;
Excel.Workbook xlWorkbook = null;
Excel.Sheets xlSheets = null;
Excel.Worksheet xlNewSheet = null;
string worksheetName ="Sheet_Name";
object readOnly1 = false;
object isVisible = true;
object missing = System.Reflection.Missing.Value;
try
{
xlApp = new Microsoft.Office.Interop.Excel.Application();
if (xlApp == null)
return;
// Uncomment the line below if you want to see what's happening in Excel
// xlApp.Visible = true;
xlWorkbook = xlApp.Workbooks.Open(#"C:\Book1.xls", missing, readOnly1, missing, missing, missing, missing, missing, missing, missing, missing, isVisible, missing, missing, missing);
xlSheets = (Excel.Sheets)xlWorkbook.Sheets;
// The first argument below inserts the new worksheet as the first one
xlNewSheet = (Excel.Worksheet)xlSheets.Add(xlSheets[1], Type.Missing, Type.Missing, Type.Missing);
xlNewSheet.Name = worksheetName;
xlWorkbook.Save();
xlWorkbook.Close(Type.Missing, Type.Missing, Type.Missing);
xlApp.Quit();
}
finally
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlNewSheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheets);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkbook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
//xlApp = null;
}
You can use OLEDB to create and manipulate Excel files. See this question for links and samples.
Here are a couple things I figured out:
You can't open more than one instance of the same object at the same time. For Example if you instanciate a new excel sheet object called xlsheet1 you have to release it before creating another excel sheet object ex xlsheet2. It seem as COM looses track of the object and leaves a zombie process on the server.
Using the open method associated with excel.workbooks also becomes difficult to close if you have multiple users accessing the same file. Use the Add method instead, it works just as good without locking the file. eg. xlBook = xlBooks.Add("C:\location\XlTemplate.xls")
Place your garbage collection in a separate block or method after releasing the COM objects.
COM is definitely not a good way to go. More specifically, it's a no go if you're dealing with web environment...
I've used with success the following open source projects:
ExcelPackage for OOXML formats (Office 2007)
NPOI for .XLS format (Office 2003)
Take a look at these blog posts:
Creating Excel spreadsheets .XLS and .XLSX in C#
NPOI with Excel Table and dynamic Chart
This is what i used to add addtional worksheet
Workbook workbook = null;
Worksheet worksheet = null;
workbook = app.Workbooks.Add(1);
workbook.Sheets.Add();
Worksheet additionalWorksheet = workbook.ActiveSheet;
I had a similar problem application-level add-in in VSTO, the exception HRESULT: 0x800A03EC when adding new sheet.
The error code 0x800A03EC (or -2146827284) means NAME_NOT_FOUND; in
other words, you've asked for something, and Excel can't find it.
Dominic Zukiewicz # Excel error HRESULT: 0x800A03EC while trying to get range with cell's name
Then I finally realized ThisWorkbook triggered the exception. ActiveWorkbook went OK.
Excel.Worksheet newSheetException = Globals.ThisAddIn.Application.ThisWorkbook.Worksheets.Add(Type.Missing, sheet, Type.Missing, Type.Missing);
Excel.Worksheet newSheetNoException = Globals.ThisAddIn.Application.ActiveWorkbook.Worksheets.Add(Type.Missing, sheet, Type.Missing, Type.Missing);

Categories

Resources