I have a folder on my PC containing multiple Excel spreadsheets that are all marked as read-only.
The folder is synced to my company's Sharepoint via OneDrive.
When I try to programmatically read data from one of these sheets via Microsoft.Office.Interop.Excel, I keep getting the You cannot use this command on a protected sheet error.
Here's the code I use to open the file:
public ExcelReader(String filePath)
{
this.filePath = filePath;
FileName = filePath.Substring(filePath.LastIndexOf("\\")+1);
app = new Excel.Application();
app.DisplayAlerts = false;
workbook = app.Workbooks.Open(filePath, false, true); //open in read only
}
public void openSheet(String sheet)
{
SheetName = sheet;
worksheet = workbook.Sheets[sheet];
Excel.Range last = worksheet.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
ColumnsTotal = last.Column;
RowsTotal = last.Row;
}
The line that throws the exception is Excel.Range last = worksheet.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);.
I figured that since I explicitly tell the Workbook to open in Read-only mode, and since I never modify the content of these files, the fact that files are read-only shouldn't be a problem.
What am I doing wrong here? How do I read the content of these files without unprotecting them (I can't do that for security reasons)?
Related
I am using Office.Interop.Excel to read data from Excel using C# ASP.Net & Dotnet 6.
I can read the Data and everything seems to be working fine.
But I have a challenge here.
The excel which I am reading data from would be updated every second.
But I am seeing an error while trying to open it and update random data.
The error says that the file is locked for editing.
Please have a look at the code below:
public double GetGoldPrice()
{
string filename = #"D:\Test.xlsx";
int row = 1;
int column = 1;
Application excelApplication = new Application();
Workbook excelWorkBook = excelApplication.Workbooks.Open(filename);
string workbookName = excelWorkBook.Name;
int worksheetcount = excelWorkBook.Worksheets.Count;
if (worksheetcount > 0)
{
Worksheet worksheet = (Worksheet)excelWorkBook.Worksheets[1];
string firstworksheetname = worksheet.Name;
var data = ((Microsoft.Office.Interop.Excel.Range) worksheet.Cells[row, column]).Value;
excelApplication.Quit();
return data;
}
else
{
Console.WriteLine("No worksheets available");
excelApplication.Quit();
return 0;
}
}
My end goal is to get live data from Excel whenever I fire the function.
The Excel would be open and can be editing any time.
Please help!
You said your file is xlsx so you would be better not using Interop but Open XML SDK 2.5. Then you can open the file in read only mode:
using (SpreadsheetDocument spreadsheetDocument =
SpreadsheetDocument.Open(fileName, false))
{
// Code removed here.
}
Check here to get familiar with Open XML SDK
I work on a project where I'd like to save some data in an Excel sheet,
Here is my code:
private void myButton11_Click(object sender, EventArgs e)
{
Microsoft.Office.Interop.Excel.Application excel;
Microsoft.Office.Interop.Excel.Workbook excelworkbook;
Microsoft.Office.Interop.Excel.Worksheet excelsheet;
excel = new Microsoft.Office.Interop.Excel.Application();
excel.Visible = false;
excel.DisplayAlerts = false;
excelworkbook = excel.Workbooks.Add(Type.Missing);
excelsheet = (Microsoft.Office.Interop.Excel.Worksheet)excelworkbook.ActiveSheet;
excelsheet.Name = "dataToExcel";
// fill in data
excelsheet.Cells[1, 1] = "test";
excelsheet.Cells[3, 3] = "test2";
// save excel
excelworkbook.SaveAs(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "//dataToExcel.xls",
Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookNormal);
true, true, 1, 10, false);
}
The problem is when executing it crashes and shows me this error message:
System.Runtime.InteropServices.COMException
HResult=0x800A03EC
Message=Coudn't access file. Please try thoses options :
• Make sure the file exist.
• Make sure the file is not in read only.
• Make sure file path isn't containing thoses characteres: < > ? [ ] : | or *
• Make sure the file path and names do not take more than 218 caracteres.
C:\Users\corentin.boudaud\source\repos\FabLoop_project_V0.0.0\FabLoop_project_V0.0.0\Program.cs :ligne 20
The crash occurs on "SaveAs", the file I'm writing to is in my documents (public, write available)
Any idea where the problem might come from?
Thanks
You can save it easy as a .csv file. CSV is also a tabel and if you open it it will open in excel.
You can do this with System.IO
Thats a csv file in excel:
and thats a csv file in notepad++
I found the problem,
when using excelworkbook.SaveAs(), the path need to be using '\' to set the path and not '/'
I can then save the file as I want, .csv .xls or .xlsx
I'm currently trying to copy a worksheet from a different workbook which i succeed by using Copy() and PasteSpecial(). However, I would like to know why the following code does not work even though many solutions online seems to use this approach.
Workbook currBook = Globals.ThisAddIn.GetActiveWorkbook();
Workbook copyBook = Globals.ThisAddIn.OpenWorkbook(Globals.ThisAddIn.Application.ActiveWorkbook.Path + #"\copyFile.xlsm", true, true);
//required worksheet
Worksheet copySheet = Globals.ThisAddIn.GetWorksheet(copyBook, "ToCopy");
copySheet.Copy(currBook.Worksheets[1]);
//close workbook
copyBook.Close();
Function used to get specific sheet:
public Excel.Worksheet GetWorksheet(Excel.Workbook book, string sheetName, bool create = false)
{
foreach (Excel.Worksheet sheet in book.Worksheets)
{
//worksheet with name found
if (sheet.Name == sheetName)
{
sheet.Activate();
return sheet;
}
}
//worksheet can't be found
if (create)
{
Excel.Worksheet sheet = book.Worksheets.Add();
sheet.Name = sheetName;
sheet.Activate();
return sheet;
}
return null;
}
There is no error from the stated code and the worksheet has been tested to exist. The program simply does not create a copy into currBook
Interestingly, I was just working on something else where this came up...
In order to specify a destination it's necessary to use Range.Copy, not Sheet.Copy:
copySheet.UsedRange.Copy(currBook.Worksheets[1].Range["A1"]);
If a destination can't be specified, then Excel puts the data in a new workbook.
I'm wondering if it is possible to write to an Excel file using C#/EPPlus while I have the file open. I continue to get exceptions while trying to write using my program and I can't find anything online.
Here is the code I have to append to an existing worksheet which works fine when the spreadsheet isn't opened
public static void AppendExistingMailingWorkbook(string workSheet, string filePath, IList<MailingReportItem> reportData)
{
//create a fileinfo object of an excel file on the disk
FileInfo file = new FileInfo(filePath);
Object thisLock = new Object();
lock (thisLock)
{
//create a new Excel package from the file
using (ExcelPackage excelPackage = new ExcelPackage(file))
{
ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets[workSheet];
var rowToAppend = worksheet.Dimension.End.Row + 1;
for (int i = 0; i < reportData.Count; i++, rowToAppend++)
{
worksheet.Cells[rowToAppend, 1].Value = reportData[i].BatchDate.Date.ToString("MM/dd/yyyy");
worksheet.Cells[rowToAppend, 2].Value = reportData[i].BatchId;
worksheet.Cells[rowToAppend, 3].Value = reportData[i].FileName;
worksheet.Cells[rowToAppend, 4].Value = reportData[i].PageCount;
worksheet.Cells[rowToAppend, 5].Value = reportData[i].MailDate;
}
//save the changes
excelPackage.Save();
}
}
}
In Excel, set the workbook to be shared. From the office help:
Open workbook in Excel
Click Review > Share Workbook
On the Editing tab, select the Allow changes by more than one user ... check box.
On the Advanced tab, select the options that you want to use for tracking and updating changes, and then click OK.
If this is a new workbook, type a name in the File name box. Or, if this is an existing workbook, click OK to save the workbook.
If the workbook contains links to other workbooks or documents, verify the links and update any links that are broken.
Click File > Save.
When you're done, - Shared will appear at the top of the Excel window, next to the filename.
The file will then be opened non-exclusively, allowing others to edit it while Excel has it open.
I'm using Excel = Microsoft.Office.Interop.Excel to write various data to Excel sheets.
Excel.Workbook wb = null;
Excel.Worksheet ws = null;
Excel.Application excelApp = new Excel.Application();
excelApp.Visible = true;
try {
// Create new workbook
wb = (Excel.Workbook)(excelApp.Workbooks.Add(Type.Missing));
ws = wb.ActiveSheet as Excel.Worksheet;
// write data ...
// Save & Close
excelApp.DisplayAlerts = false; // Don't show file dialog for overwrite
wb.Close(true, targetFilename, Type.Missing);
} finally {
// Close the Excel process
if (null != ws)
Marshal.ReleaseComObject(ws);
if (null != wb)
Marshal.ReleaseComObject(wb);
excelApp.Quit();
Marshal.ReleaseComObject(excelApp);
GC.Collect();
}
This code is exectued by multiple threads at a time, and it's been working almost always. Even the Excel processes disappear in task manager.
However, sometimes a System.Runtime.InteropServices.COMException is thrown at wb.Close(true, targetFilename, Type.Missing). It claims that access on the target filename was denied. Though I've been making sure that the target filenames are unique.
May the exception be due to any bad handling of Excel or maybe that I'm using threads?
Apparently, targetFilename wasn't really unique. There was one single difference in upper/lower case spelling, and it seems like two threads tried to write to the same file at once. The issue was easily solvable by using targetFilename.ToLower().
Anyway, if you discover any further potential issues, please leave a comment.