I am wondering why this code gets the open worksheet when I run it in debug, and catch an exception when I run it with no debug..
Excel.Application xlApp = null;
Excel.Workbook xlWBook = null;
Excel.Worksheet xlWSheet = null;
Excel.Range xlRange = null;
try {
xlApp = (Excel.Application) Marshal.GetActiveObject("Excel.Application");
xlApp.Visible = true;
xlWBook = xlApp.ActiveWorkbook;
xlWSheet = xlWBook.ActiveSheet;
xlRange = xlWSheet.UsedRange;
logResult = logResult + "Agganciato " + xlWBook.Name + " \r\n";
} catch {
logResult = logResult + "Nessun file aperto rilevato. \r\n";
}
Any suggestion?
The following shows how one can use Excel Interop to either interact with an open Excel workbook or create a new workbook if one isn't open.
Try the following:
Add Reference (Option 1)
Download / install NuGet package: Microsoft.Office.Interop.Excel
Add Reference (Option 2)
In VS menu, click Project
Select Add Reference...
Click COM
Check Microsoft Excel xx.x Object Library (ex: Microsoft Excel 16.0 Object Library)
Add the following using directives:
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;
CreateExcelWorkbook
public void CreateExcelWorkbook(string filename)
{
bool isExcelAlreadyRunning = false;
string logResult = string.Empty;
Excel.Application xlApp = null;
Excel.Workbook xlWBook = null;
Excel.Worksheet xlWSheet = null;
Excel.Range xlRange = null;
try
{
try
{
//if Excel isn't open, this will throw a COMException
xlApp = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
//set value
isExcelAlreadyRunning = true;
}
catch (System.Runtime.InteropServices.COMException ex)
{
//create new instance
xlApp = new Excel.Application();
}
//whether or not to make Excel visible
xlApp.Visible = true;
//prevent prompting to overwrite existing file
xlApp.DisplayAlerts = false;
//disable user control while modifying the Excel Workbook
//to prevent user interference
//only necessary if Excel application Visibility property = true
//need to re-enable before exitin this method
//xlApp.UserControl = false;
if (xlApp.Workbooks.Count > 0)
xlWBook = xlApp.ActiveWorkbook;
else
xlWBook = xlApp.Workbooks.Add();
if (xlWBook.Worksheets.Count > 0)
xlWSheet = xlWBook.ActiveSheet;
else
xlWSheet = xlWBook.Sheets.Add();
xlRange = xlWSheet.UsedRange;
//set value
xlWSheet.Cells[1, 1] = $"Test {DateTime.Now.ToString("HH:mm:ss.fff")}";
//save Workbook - if file exists, overwrite it
// xlWBook.SaveAs(filename, Excel.XlFileFormat.xlWorkbookDefault, System.Reflection.Missing.Value, System.Reflection.Missing.Value, true, false, Excel.XlSaveAsAccessMode.xlNoChange, Excel.XlSaveConflictResolution.xlLocalSessionChanges, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
xlWBook.SaveAs(filename, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, Excel.XlSaveAsAccessMode.xlNoChange, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
logResult = logResult + "Agganciato " + xlWBook.Name + " \r\n";
}
catch
{
logResult = logResult + "Nessun file aperto rilevato. \r\n";
}
finally
{
if (xlWBook != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlRange);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlRange);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWSheet);
xlWSheet = null;
xlRange = null;
if (!isExcelAlreadyRunning)
{
//close workbook
xlWBook.Close(false);
}
//release all resources
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWBook);
xlWBook = null;
}
System.Threading.Thread.Sleep(150);
if (xlApp != null)
{
if (!isExcelAlreadyRunning)
{
xlApp.Quit();
}
//release all resources
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlApp);
xlApp = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
System.Threading.Thread.Sleep(175);
}
}
}
Usage:
CreateExcelWorkbook(filename);
//the following is necessary otherwise the Excel process seems to persist in Task Manager
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
Resources:
Microsoft.Office.Interop.Excel Namespace
Excel is still running though I quit and released the object
Cannot close Excel.exe after Interop process
Related
Brief details:
Running Office 360 with Excel 64bit installed.
Application is built on .NET 4.6 and CPU type is set to x64
The code that's not working - line marked where it fails
public bool CreateInvoice()
{
try
{
//Write file
var setting = new Classes.Settings();
string WritePath = setting.DefaultSavePath + "\\Invoices\\" + InvoiceDetails.CustomerID + "\\" + InvoiceDetails.InvoiceNumber + ".xlsx";
if (!System.IO.Directory.Exists(setting.DefaultSavePath + "\\Invoices\\" + InvoiceDetails.CustomerID))
System.IO.Directory.CreateDirectory(setting.DefaultSavePath + "\\Invoices\\" + InvoiceDetails.CustomerID);
if (System.IO.File.Exists(WritePath))
System.IO.File.Delete(WritePath);
System.IO.File.WriteAllBytes(WritePath, AccountManagement.Properties.Resources.Invoice);
//Prepare Excel
Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbooks xlWorkBooks = null;
Microsoft.Office.Interop.Excel.Workbook xlWorkBook = null;
Microsoft.Office.Interop.Excel.Sheets xlSheets = null;
Microsoft.Office.Interop.Excel.Worksheet xlExportSheet = null;
Classes.GetExcelProcessID getExcelProcessID = new GetExcelProcessID();
xlWorkBooks = xlApp.Workbooks; //***********FAILS HERE*************
xlWorkBook = xlWorkBooks.Add(WritePath);
xlSheets = xlApp.Worksheets;
xlExportSheet = (Microsoft.Office.Interop.Excel.Worksheet)(xlSheets[1]);
var cells = xlExportSheet.Cells;
var Process = Classes.GetExcelProcessID.ExcelProcesID(xlApp);
try
{
xlApp.Visible = false;
xlApp.DisplayAlerts = false;
//This is where I make my edits.
xlWorkBook.SaveAs(WritePath, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing);
xlWorkBook.ExportAsFixedFormat(Microsoft.Office.Interop.Excel.XlFixedFormatType.xlTypePDF, setting.DefaultSavePath + "\\Invoices\\" + InvoiceDetails.CustomerID + "\\" + InvoiceDetails.InvoiceNumber + ".pdf");
InvoiceSavePath = setting.DefaultSavePath + "\\Invoices\\" + InvoiceDetails.CustomerID + "\\" + InvoiceDetails.InvoiceNumber + ".pdf";
InvoiceDetails.InvoiceSavePath = InvoiceSavePath;
}
catch (Exception ex)
{
return false;
}
finally
{
//Ensue all COM objects are closed and realesed or EXCEl will remain open.
xlWorkBook.Close(0, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
xlWorkBooks.Close();
//xlApp.Application.Quit();
xlApp.Quit();
while (Marshal.FinalReleaseComObject(xlApp) != 0) { }
while (Marshal.FinalReleaseComObject(xlWorkBooks) != 0) { }
while (Marshal.FinalReleaseComObject(xlWorkBook) != 0) { }
while (Marshal.FinalReleaseComObject(xlSheets) != 0) { }
while (Marshal.FinalReleaseComObject(xlExportSheet) != 0) { }
while (Marshal.FinalReleaseComObject(cells) != 0) { }
xlApp = null;
xlWorkBooks = null;
xlWorkBook = null;
xlSheets = null;
xlExportSheet = null;
cells = null;
try
{
Process.Kill();
}
catch
{
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return false;
}
return true;
}
This is the exception I keep getting.
Unable to cast COM object of type 'Microsoft.Office.Interop.Excel.ApplicationClass' to interface type 'Microsoft.Office.Interop.Excel._Application'
I initially thought the issue was about my application possibly still being built at x86 but I have a interop function with Word that runs perfectly fine - and that's 64bit.
I've tried google but all the fixes are to do with 64bit office and a 32bit application.
Any tips?
I am running a script to format sheets in an existing excel file. Here is what I have now:
public void Main()
{
string datetime = DateTime.Now.ToString("yyyyMMddHHmm");
try
{
string FileName = Dts.Variables["User::DestinationFilePath1"].Value.ToString();
string FolderName = Dts.Variables["User::DestinationFolder1"].Value.ToString();
Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
xlApp.Visible = false;
Workbook xlWorkbook = xlApp.Workbooks.Open(FileName);
Sheets xlSheets = xlWorkbook.Worksheets;
Worksheet sheet = (Worksheet)xlApp.Worksheets[1];
sheet.Select(Type.Missing);
xlWorkbook.Save();
xlWorkbook.Close(true);
Dts.TaskResult = (int)ScriptResults.Success;
}
catch (Exception exception)
{
// Create Log File for Errors
using (StreamWriter sw = File.CreateText(Dts.Variables["User::DestinationFilePath1"].Value.ToString() + datetime + ".log"))
{
sw.WriteLine(exception.ToString());
Dts.TaskResult = (int)ScriptResults.Failure;
}
}
}
It doesn't do anything at the moment, just opens the workbook and sets the active worksheet. There are 3 different sheets in the workbook that I need to format, so would I be able to do this like so?:
try
{
string FileName = Dts.Variables["User::DestinationFilePath1"].Value.ToString();
string FolderName = Dts.Variables["User::DestinationFolder1"].Value.ToString();
Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
xlApp.Visible = false;
Workbook xlWorkbook = xlApp.Workbooks.Open(FileName);
Sheets xlSheets = xlWorkbook.Worksheets;
Worksheet sheet = (Worksheet)xlApp.Worksheets[1];
sheet.Select(Type.Missing);
//do work here
Worksheet sheet = (Worksheet)xlApp.Worksheets[2];
sheet.Select(Type.Missing);
//do work here
Worksheet sheet = (Worksheet)xlApp.Worksheets[3];
sheet.Select(Type.Missing);
//do work here
xlWorkbook.Save();
xlWorkbook.Close(true);
Dts.TaskResult = (int)ScriptResults.Success;
}
I've made an application that logs data to an excel file.
I can't open the excel file until I've closed the application.
In task manager excel.exe is still running after I've closed the excel application in code.
I've tried at least 11 ways of closing excel but it doesn't work.
All the code is executed from a thread:
thread = new Thread(() => export_parameters(path));
public class xlsx_logfile
{
private Microsoft.Office.Interop.Excel._Application excel;//excel application that is used for creating excel workbooks(files)
private Microsoft.Office.Interop.Excel.Workbooks workbooks;
private Microsoft.Office.Interop.Excel._Workbook workbook;//excel workbook(file)
private Microsoft.Office.Interop.Excel._Worksheet worksheet;
private string filename;
public xlsx_logfile(string path)
{
//destructor?
excel = new Microsoft.Office.Interop.Excel.Application();
workbooks = excel.Workbooks;
workbook = workbooks.Add(Type.Missing);
worksheet = null;
worksheet = workbook.ActiveSheet;
worksheet.Name = "sensordata";
filename = path;
}
public void column_add(uint column_zerobased_index,string header, string format, double[] data)
{
Microsoft.Office.Interop.Excel.Range formatRange;
Microsoft.Office.Interop.Excel.Range c1;
//Microsoft.Office.Interop.Excel.Range c2;
column_zerobased_index = 0;
//var worksheet = workbook.ActiveSheet;
c1 = worksheet.Cells[1, column_zerobased_index+1];
//c2 = oSheet.Cells[4, 4];
formatRange = worksheet.get_Range(c1,c1);//column_zerobased_index + 1
formatRange.EntireColumn.NumberFormat = "0.0";
worksheet.Cells[1, column_zerobased_index+1].NumberFormat = "#";
worksheet.Cells[1, column_zerobased_index + 1] = header;
//todo use: https://stackoverflow.com/questions/3989122/microsoft-office-interop-excel-really-slow
for (int i = 0; i < data.Length; ++i)
{
worksheet.Cells[i + 1 + 1, column_zerobased_index+1] = data[i];
}
// Cleanup
GC.Collect();
GC.WaitForPendingFinalizers();
System.Runtime.InteropServices.Marshal.ReleaseComObject(formatRange);
System.Runtime.InteropServices.Marshal.ReleaseComObject(c1);
}
void close(string filename)
{
//worksheet = null;
//workbook.Close();
//workbook = null;
//excel = null;
//excel.Quit();
//worksheet = null;
//workbook = null;
//excel = null;
//worksheet = null;
//workbook.Close();
//workbook = null;
//excel.Quit();
//excel = null;
//worksheet = null;
//workbook.Close();
//workbook = null;
//var workbooks_local = excel.Workbooks;
//var workbook_local = workbooks_local.Open(filename);
//workbook_local.Close();
//workbooks_local.Close();
//excel.Quit();
//System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook_local);
//System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks_local);
//System.Runtime.InteropServices.Marshal.ReleaseComObject(excel);
//System.Runtime.InteropServices.Marshal.ReleaseComObject(worksheet);
//worksheet = null;
////workbook.Close();
//System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
//workbook = null;
////excel.Quit();
//System.Runtime.InteropServices.Marshal.ReleaseComObject(excel);
//excel = null;
////based on https://stackoverflow.com/questions/1526685/c-how-can-i-open-and-close-an-excel-workbook
//workbook.Close(false, filename, null);
//System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
//excel.Quit();
//System.Runtime.InteropServices.Marshal.ReleaseComObject(excel);
//workbook = null;
//excel = null;
//GC.Collect();
//GC.WaitForPendingFinalizers();
//GC.Collect();
//GC.WaitForPendingFinalizers();
//var aap = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
//System.Runtime.InteropServices.Marshal.ReleaseComObject(worksheet);
//worksheet = null;
//workbook.Close();
//System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
//workbook = null;
//workbooks.Close();
//System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks);
//workbooks = null;
//excel.Quit();
//System.Runtime.InteropServices.Marshal.ReleaseComObject(excel);
//excel = null;
// Cleanup
GC.Collect();
GC.WaitForPendingFinalizers();
//System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlRng);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(worksheet);
workbook.Close(Type.Missing, Type.Missing, Type.Missing);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(workbook);
excel.Quit();
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excel);
}
public void save()
{
workbook.SaveAs(filename);
close(filename);
}
}
edit: this question is different from Closing Excel Application Process in C# after Data Access because I'm executing from a thread, not a method. The provided answers didn't work.
I solved the problem myself:
private Microsoft.Office.Interop.Excel._Application excel;//excel application that is used for creating excel workbooks(files)
private Microsoft.Office.Interop.Excel._Workbook workbook;//excel workbook(file)
private Microsoft.Office.Interop.Excel._Worksheet worksheet;
excel = new Microsoft.Office.Interop.Excel.Application();
workbook = excel.Workbooks.Add();
worksheet = workbook.ActiveSheet;
workbook.Close();
excel.Quit();
GC.Collect();
GC.WaitForPendingFinalizers();
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(worksheet);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(workbook);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excel);
worksheet = null;
workbook = null;
excel = null;
I'm working on c# windows application with SQL server.
I'm getting an error like the following when tried to do Save-as in excel in c#. But inside workbook.open statement and workbook.saveas am changing readonly attribute as false.I need to save the excel with the same name only.Can anybody please help me.
Cannot access readonly document filename.xlsx
private static Microsoft.Office.Interop.Excel.Workbook mWorkBook;
private static Microsoft.Office.Interop.Excel.Sheets mWorkSheets;
private static Microsoft.Office.Interop.Excel.Worksheet mWSheet1;
private static Microsoft.Office.Interop.Excel.Application oXL;
string path = #"D:\Test\test.xlsx";
oXL = new Microsoft.Office.Interop.Excel.Application();
oXL.Visible = true;
oXL.DisplayAlerts = false;
mWorkBook = oXL.Workbooks.Open(path, 0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
//Get all the sheets in the workbook
mWorkSheets = mWorkBook.Worksheets;
//Get the allready exists sheet
mWSheet1 = Microsoft.Office.Interop.Excel.Worksheet)mWorkSheets.get_Item("Sheet1");
mWSheet1.Cells[i+2, 5] = DBDaysWorked;
mWorkBook.SaveAs(path, System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
false,false, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlShared,
false,
false,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value);
mWorkBook.Close(Missing.Value, Missing.Value, Missing.Value);
mWSheet1 = null;
mWorkBook = null;
oXL.Quit();
GC.WaitForPendingFinalizers();
GC.Collect();
The problem is with the flag XlSaveAsAccessMode.xlShared when saving the document, it throws the error:
This workbook cannot be shared because privacy has been enabled for this workbook. To share this workbook, click the File tab, and then click Excel Options. In the Excel Options dialog box, click Trust Center, and then click the Trust Center Settings button. In the Privacy Options category, clear the check box next to the option Remove personal information from file properties on save.
Removing this option does indeed fix the error. Alternatively setting the flag to XlSaveAsAccessMode.xlNoChange works if you're not bothered about sharing the workbook.
I'm not sure if you can automate removing this property from a workbook to prevent the error.
For the record, I found this by simply wrapping your code in a try/catch and throwing an error...
Garbage Collection
Before the try block that you should have now added hint hint ;-)
Initialise everything to null so that it will be accessible in the finally block.
Microsoft.Office.Interop.Excel.Workbook mWorkBook = null;
Microsoft.Office.Interop.Excel.Sheets mWorkSheets = null;
Microsoft.Office.Interop.Excel.Worksheet mWSheet1 = null;
Microsoft.Office.Interop.Excel.Application oXL = null;
You normal code is fine and can go in the try block. Catch only errors you can handle and recover from. Then in the finally block:
if (mWorkBook != null)
{
mWorkBook.Close(Missing.Value, Missing.Value, Missing.Value);
}
if (oXL != null)
{
oXL.Quit();
if (mWSheet1 != null)
{
Marshal.FinalReleaseComObject(mWSheet1);
mWSheet1 = null;
}
if (mWorkSheets != null)
{
Marshal.FinalReleaseComObject(mWorkSheets);
mWorkSheets = null;
}
if (mWorkBook != null)
{
Marshal.FinalReleaseComObject(mWorkBook);
mWorkBook = null;
}
Marshal.FinalReleaseComObject(oXL);
oXL = null;
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
Hi all am creating a excel using Microsoft office interop.and it creates files successfully.But the problem is that when it creates a files it just opens excel adds the value in to excel and saves it in the specified name.Any accidental typing at that time results leads to a exception.Am creating nearly 75 files with many rows from database and hence takes time.During the processing am unable to do any task since it creates exception if its typed in the excel.Is there any way to run the process in background so that excel application does not open for each file creation.
Excel.Application oXL;
Excel.Workbook oWB;
Excel.Worksheet oSheet;
Excel.Range oRange;
// Start Excel and get Application object.
oXL = new Excel.Application();
// Set some properties
oXL.Visible = true;
oXL.DisplayAlerts = false;
// Get a new workbook.
oWB = oXL.Workbooks.Add(Missing.Value);
// Get the active sheet
oSheet = (Excel.Worksheet)oWB.ActiveSheet;
oSheet.Name = "Sales";
// Process the DataTable
// BE SURE TO CHANGE THIS LINE TO USE *YOUR* DATATABLE
DataTable dt = dtt;
int rowCount = 1;
foreach (DataRow dr in dt.Rows)
{
rowCount += 1;
for (int i = 1; i < dt.Columns.Count + 1; i++)
{
// Add the header the first time through
if (rowCount == 2)
{
oSheet.Cells[1, i] = dt.Columns[i - 1].ColumnName;
}
oSheet.Cells[rowCount, i] = dr[i - 1].ToString();
}
}
// Resize the columns
//oRange = oSheet.get_Range(oSheet.Cells[1, 1],
// oSheet.Cells[rowCount, dt.Columns.Count]);
oRange = oSheet.Range[oSheet.Cells[1, 1], oSheet.Cells[rowCount, dt.Columns.Count]];
oRange.EntireColumn.AutoFit();
// Save the sheet and close
// oSheet = null;
oRange = null;
oWB.SaveAs("" + username + " .xls", Excel.XlFileFormat.xlWorkbookNormal,
Missing.Value, Missing.Value, Missing.Value, Missing.Value,
Excel.XlSaveAsAccessMode.xlExclusive,
Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Missing.Value);
oWB.Close(Missing.Value, Missing.Value, Missing.Value);
oWB = null;
oXL.Quit();
// Clean up
// NOTE: When in release mode, this does the trick
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
By default Excel via Interop opens as Invisible.
It's your code that change the visibility of Excel.
Remove the line
oXL.Visible = true;
or set to false
oXL.Visible = false;
Try this...
// Start Excel and get Application object. oXL = new Excel.Application {Visible = false};
OR -
// Set some properties oXL.Visible = false;