Trying to figure out why my EXCEL*32 process remains in use until both the my application AND the excel file are closed. I must be missing something after creation, it's like the application is holding onto the EXCEL *32 resource after this code. Any suggestions to get it to 'let go' after it's export operation is completed?
Also, I do not want to close the newly created Excel sheet, I just want to release the resource being used in relation to my actual .net application.
Application xls = new Application();
xls.SheetsInNewWorkbook = 1;
// Create our new excel application and add our workbooks/worksheets
Workbook Workbook = xls.Workbooks.Add();
Worksheet CrossoverPartsWorksheet = xls.Worksheets[1];
// Create our new excel application and add our workbooks/worksheets
Workbook Workbook = xls.Workbooks.Add();
Worksheet CrossoverPartsWorksheet = xls.Worksheets[1];
/////////////////////////////////////////
// < DO EXCEL EXPORT OPERATIONS HERE > //
/////////////////////////////////////////
// Release our resources.
Marshal.ReleaseComObject(Workbook);
Marshal.ReleaseComObject(CrossoverPartsWorksheet);
Marshal.ReleaseComObject(xls);
When you write
Workbook Workbook = xls.Workbooks.Add();
CLR creates RCW (Runtime Callable Wrapper) objects not only for Workbook, but for Workbooks collection too(coz you need object that then will be used for Add() method). And if CLR creates RCW object and you do not keep reference - you can't finalize it.
So, the main rule:
You should avoid double-dot-calling expressions:
var workbooks = xls.Workbooks;
var workbook = workbooks.Add();
Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(workbooks);
Marshal.FinalReleaseComObject(xls) is what your looking for.
Related
this is my code, I have seen others closing excel sheets this way but why does this not work. There are no errors in the code execution but the app still seems to be running in the background
Microsoft.Office.Interop.Excel.Application Excel = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook Sheet = Excel.Workbooks.Open("C:\\Users\\Maxine\\Testing.xlsx");
Microsoft.Office.Interop.Excel.Worksheet x = ((Microsoft.Office.Interop.Excel.Worksheet)Excel.ActiveSheet);
Sheet.Close(false,Type.Missing,Type.Missing);
Excel.Quit();
You need to actually release the COM object. See here, but you need to do Marshal.FinalReleaseComObject on the Excel object.
I have created a number of unit tests. At the beginning of each test I open a blank excel workbook on the TestInitialize however for this particular test I need to open another excel workbook. I want to open it inside the blank workbook opened on the TestInitialize . I tried doing the following however it opens them as 2 separate workbooks.
Any ideas why this is happening?
My code is as follows
using xl = Microsoft.Office.Interop.Excel;
private static string columnChartTemp = #"Testing\V8\TestMaster\V8.6\Testing\V8.6.0.11 Testing\columnChart.xlsx";
var excel = (xl.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
var myWorkbook = excel.Workbooks.Open(columnChartTemp);
excel.Visible = true;
A workbook is a file containing one or more worksheets (tabs.) You can't open a workbook inside of another workbook.
It sounds like you want to take a worksheet that's in a workbook and add it to another workbook. You can do that. Open both workbooks and copy the sheet from one to the other.
at the moment my current process is as followed. Query database - > Save file locally -> Open Workbook using Excel Interop Dll, Make Changes To Work Book, Save As using Excel Interop Dll. The reason for save as is because I require some addition settings so the file isn't set to read only.
The issue I'm coming across is that it's saving locally twice. First time is fine, second time a prompt will appear asking if I would like to override. I'm wondering how can I remove the Save File Locally process and have it in memory to work with? If I am able to work with the file in memory, I would have the prompt on Save As asking me if I would like to override the previous file.
Code:
//Save File Locally
System.IO.File.WriteAllBytes(saveFileDialog.FileName, Report.FileArray);
var fileLocation = saveFileDialog.InitialDirectory + saveFileDialog.FileName;
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
// Open Workbook Using Excel Interop Dll
Workbook wb = excel.Workbooks.Open(fileLocation);
Worksheet ws1 = wb.Worksheets.get_Item("English");
//Make Changes To WorkBook
ws1.Range["E5"].Value = StartDate;
ws1.Range["G5"].Value = EndDate;
// Save AS Using Excel Interop With shared settings to remove read only access
wb.SaveAs(fileLocation, AccessMode: XlSaveAsAccessMode.xlShared);
Process.Start(fileLocation);
You'd better disable the prompt, to what I remember this is possible but it imply a lot of umnaged code...
Try this
Microsoft.Office.Interop.MSProject.Application msProjectApp = new Microsoft.Office.Interop.MSProject.Application();
msProjectApp.DisplayAlerts = false;
Edit
Microsoft.Office.Interop.Excel.Application msProjectApp = new Microsoft.Office.Interop.Excel.Application();
msProjectApp.Visible = true; //show the application and not need to start a process
msProjectApp.DisplayAlerts = false;
//Save File Locally
System.IO.File.WriteAllBytes(saveFileDialog.FileName, Report.FileArray);
var fileLocation = saveFileDialog.InitialDirectory + saveFileDialog.FileName;
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
// Open Workbook Using Excel Interop Dll
Workbook wb = excel.Workbooks.Open(fileLocation);
Worksheet ws1 = wb.Worksheets.get_Item("English");
//Make Changes To WorkBook
ws1.Range["E5"].Value = StartDate;
ws1.Range["G5"].Value = EndDate;
// Save Only
wb.Save();
Remove Process.Start
excel.Visible = true;
excel.DisplayAlerts = false;
If you "own" the workbook and can set it up beforehand to play nice and are only loading in data, I find the OleDB Access SQL connection approach to be a better way to load raw data into SQL.
I'm working on a C# project that uses Microsoft.Office.Interop.Excel.Application to read values from an Excel file:
try {
Application xlApp = new Application();
Workbook workbook = xlApp.Workbooks.Open(filename)
// ... Load Excel values ...
} finally {
// ... Tidy up ...
}
In the finally block I'd like to make sure everything is closed and disposed of properly so nothing hangs around in memory and Excel closes cleanly. Have seen various threads about what this code should look like (more complex than I thought!) but one thing it might include is:
if (workbook != null) {
workbook.Close();
// ... possibly also Marshal.FinalReleaseComObject(workbook);
}
However, this throws an error if the workbook is already closed so how can I safely check this? Would prefer not to just catch the error if possible as this type of thing tends to distort debugging. Is there a clean way of finding out the workbook state before closing?
One more q - am wondering if workbook.Close() is needed if xlApp.Quit(); is done afterwards - would quitting the Excel application cause workbook.Close() (and any COM object releasing) to happen implicitly?
As you are opening the workbook the best advice is to keep track of the workbook and close it when appropriate. If your code is quite detailed then you could store a Boolean value indicating whether the file is currently open or closed.
In Excel there is no property such as IsOpen. You could try to reference the workbook:
Workbook wbTest = xlApp.Workbooks.get_Item("some.xlsx");
but this creates a COM error if the book is not open, so gets quite messy.
Instead, create your own function IsOpen that returns a boolean and loops through the currently open workbooks (the Workbooks collection) checking the name, using code like this:
foreach (_Workbook wb in xlApp.Workbooks)
{
Console.WriteLine(wb.Name);
}
workbook.Close() would not be necessary if the workbook has been saved - reflecting the normal behaviour of Excel. However, all Excel object references need to be released. As you have discovered, this is a little fiddly, and Close and Quit do not achieve this on their own.
static bool IsOpen(string book)
{
foreach (_Workbook wb in xlApp.Workbooks)
{
if (wb.Name.Contains(book))
{
return true;
}
}
return false;
}
UPDATE1:
I am using Excel 2010 and I've searched the web and found thousands upon thousands of ways to do this via win form, console, etc. But I can't find a way to do this via DLL. and none of the sample on-line is complete all in bit and pieces.
UPDATE END
I have looked and goggled but did not get the specific what i am looking for, as show below the excel sample sheet.
i'm looking a way to read and store the each cell data in a variable
i have started something like this:
Workbook workbook = open(#"C:\tmp\MyWorkbook.xls");
IWorksheet worksheet = workbook.Worksheets[0];
IRange a1 = worksheet.Cells["A1"];
object rawValue = a1.Value;
string formattedText = a1.Text;
Console.WriteLine("rawValue={0} formattedText={1}", rawValue, formattedText);
Your code can work with a couple changes.
One thing to remember is that Excel worksheets are 1-based, not 0-based (and use Worksheet instead of IWorksheet):
Worksheet worksheet = workbook.Worksheets[1];
And to get a range, it is easiest to call get_Range() on the worksheet object (and use Range instead of IRange):
Range a1 = worksheet.get_Range("A1");
With those two lines of code changed, your example will work fine.
UPDATE
Here is a "complete" example:
Right-click your project in the solution explorer and click "Add
Reference".
Click on the COM tab and sort the list by Component Name. Find "Microsoft Excel 14.0 Object Library" in the list and select it. Click OK.
In the code file where you want this to run, add a using Microsoft.Office.Interop.Excel;
Use this code, which I've modified as little as possible from your example:
var excel = new Microsoft.Office.Interop.Excel.Application();
Workbook workbook = excel.Workbooks.Open(#"C:\tmp\MyWorkbook.xls");
Worksheet worksheet = workbook.Worksheets[1];
Range a1 = worksheet.get_Range("A1");
object rawValue = a1.Value;
string formattedText = a1.Text;
Console.WriteLine("rawValue={0} formattedText={1}", rawValue, formattedText);
Excel.Sheets sheets = workbook.Worksheets;
Excel.Worksheet worksheet = (Excel.Worksheet)sheets.get_Item(1);
System.Array myvalues;
Excel.Range range = worksheet.get_Range("A1", "E1".ToString());
myvalues = (System.Array)range.Cells.Value;
If you don't want to be in a war with com components and registering dlls,
the best way to read excel is Excel Reader for .NET
I have been using it for so long time , and I can say it just works.
and excelReader.IsFirstRowAsColumnNames property makes everything easy.
You can play your data within a dataset.