I have a wpf application that opens/creates excel files and reads/writes to them. In the normal way of the application running, no excel window is shown to the user.
The Scenario:
Through my application, I browse to excel file "AAA.xlsx", and the application loads it. Then, I try to browse to another excel file, but while on the browse window I choose excel file "BBB.xlsx", right click it and select open, Excel launches with both files open.
If I do the same routine, but beforehand I had the Excel program already open(with or without a file loaded), only the selected file will open.
Below is the constructor
public ExcelManipulator()
{
excelApp = new Excel.Application();
excelApp.Visible = false; //not making any difference
excelApp.IgnoreRemoteRequests = true; //not making any difference
workbooks = excelApp.Workbooks;
workbook = workbooks.Open(path);
...
}
My ultimate goal is the excel files that my application has loaded to be invisible from the user's screen.
I think you are referring to separate 'instances' of Excel.
Try the following.
Process process = new Process();
Process.Start("Excel.exe", myExcelFile);
Other option is, if you use Interop (i.e. Microsoft.Office.Interop.Excel.dll ), you can do it as follows. This will always open the file in a new instance.
Excel.Application excelApp = new Excel.Application();
excelApp.Visible = true;
string workbookPath = (#"C:\Sample.xlsx");
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(workbookPath,
0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
Related
I'm trying to ensure that an excel file passed to my application is opened in it's own window rather than an existing Excel instance. Is there a way of telling the Process to do this? The following code always uses an existing instance if present.
Process process = new Process();
process.StartInfo.FileName = myExcelFile;
process.Start();
thanks
Matt
Try the following.
Process process = new Process();
Process.Start("Excel.exe", myExcelFile);
Other option is, if you use Interop (i.e. Microsoft.Office.Interop.Excel.dll ), you can do it as follows. This will always open the file in a new instance.
Excel.Application excelApp = new Excel.Application();
excelApp.Visible = true;
string workbookPath = (#"C:\Sample.xlsx");
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(workbookPath,
0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
I have an Excel Workbook ("test.xlsx") that has a cell named "gv_epxsize". My goal is to open the excel workbook and write down the string "101" in the cell with the name "gv_epxsize".
The problem is that my code keeps making the file Read Only, so it will not write the string "101" to the named cell. I keep receiving a windows prompt that I already have the file open with Windows privileges and asks if I want to open a Read Only copy. The problem is that I don't have the file open, and there is no EXCEL.EXE process running before I initiated the code.
What I've already done:
I've saved the file as a different name in a different folder - still no luck.
The file is not saved in a shared folder.
I have made sure my TaskManager has every EXCEL.EXE process killed before I run my code.
Can someone please show me what I'm doing wrong here?
Here's the snippet of C#
string filePath = "C:\\Users\\ussatdafa\\Desktop\\Work\\Projects\\test.xlsx";
Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
if (xlApp == null)
{
MessageBox.Show("Excel has not been properly installed");
}
else
{
//string fileName = Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), filePath);
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
Workbooks wbs = excelApp.Workbooks;
Workbook wb = wbs.Open(filePath, 0, false, 5, "", "", false, XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Worksheet ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.Worksheets.get_Item(1);
wb.Names.Item("gv_epxsize").RefersToRange.Value = "101";
}
I'm honestly not sure what's going on, but I have two observations:
You are opening Excel twice -- that appears to be certain. One instance is xlApp and the other is excelApp. If you open your task manager on the instantiation of excelApp I'm pretty sure you will find two instances of Excel running. I have no idea if that's contributing to your issue or not
I always found it helpful, when debugging, to make Excel visible. You can always comment that line out before you deploy, but during debugging it's nice since exposing COM objects during debugging isn't as helpful as native .NET objects -- this way you can see it in its native form
I ran a version of your code with these changes and had no issues changing the cell value of the named range "gv_epxsize."
string filePath = "C:\\Users\\ussatdafa\\Desktop\\Work\\Projects\\test.xlsx";
Microsoft.Office.Interop.Excel.Application excelApp =
new Microsoft.Office.Interop.Excel.Application();
if (excelApp == null)
{
MessageBox.Show("Excel has not been properly installed");
}
else
{
excelApp.Visible = true;
Workbook wb = excelApp.Workbooks.Open(filePath, 0, false, 5, "", "", false,
XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Worksheet ws = wb.Sheets[1];
wb.Names.Item("gv_epxsize").RefersToRange.Value = "101";
}
This worked flawlessly for me. Here is proof:
So that leads me to several possibilities:
(Microsoft.Office.Interop.Excel.Worksheet)wb.Worksheets.get_Item(1);
Isn't what you think it is. Or perhaps, it's not the same as what I used, which was:
Worksheet ws = wb.Sheets[1];
Which will return the first worksheet ("Sheet1" on a new workbook).
And of course, there is the possibility that having two Excels open is causing issues.
I am pretty sure your issue is with WHERE in your code you are saving the file. From your posted code, there is one thing that does not really work and could explain your problem. Take a look at the following snippet:
else {
//string fileName = Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), filePath);
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
Workbooks wbs = excelApp.Workbooks;
Workbook wb = wbs.Open(filePath, 0, false, 5, "", "", false, XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Worksheet ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.Worksheets.get_Item(1);
wb.Names.Item("gv_epxsize").RefersToRange.Value = "101";
}
This is the else portion of the if (xlApp == null) statement. First in this else portion you create a NEW Excel application called excelApp with:
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
Why you are doing this is unknown since you have already created one earlier called xlApp. But this is still ok; you are allowed to open more than one Excel application.
Then open the file and make changes:
Workbooks wbs = excelApp.Workbooks;
Workbook wb = wbs.Open(filePath, 0, false, 5, "", "", false, XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Worksheet ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.Worksheets.get_Item(1);
wb.Names.Item("gv_epxsize").RefersToRange.Value = "101";
You open a workbook using the filePath and call the woorkbook wb. Then grab the first sheet in wb and assign it to a worksheet variable ws. Keep in mind you OPEN the workbook in this else clause. Make the changes to the workbook and then exit the else clause. All seems OK EXCEPT… since we have exited the else clause... excelApp, wbs, wb and ws variables NO LONGER EXIST. Even if you tried to save or close the file outside this else clause you will have no way to reference it because you CREATED those variables inside the else clause.
Since you can not create a new variable named wb if it already exist... Then it is clear the workbook wb is never getting saved or closed.
I put the following lines INSIDE your else clause and was able to open the file correctly even with your program running. It is clear you may be saving and closing the file somewhere later in your code but it’s not the file you opened in this else clause.
else {
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
Workbooks wbs = excelApp.Workbooks;
Workbook wb = wbs.Open(filePath, 0, false, 5, "", "", false, XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Worksheet ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.Worksheets.get_Item(1);
wb.Names.Item("gv_epxsize").RefersToRange.Value = "101";
wb.Save();
wb.Close();
excelApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp);
}
Hope this makes sense.
I can't seem to find the proper way to open and close an excel file.
Here is what I have to open my file, which I find overly complicated:
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(workbookPath,
0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
Microsoft.Office.Interop.Excel.Sheets excelSheets = excelWorkbook.Worksheets;
Worksheet sheet = (Microsoft.Office.Interop.Excel.Worksheet)excelApp.Worksheets[2];
sheet.Select(Type.Missing);
I have no idea how to properly close it. I need to save it with the same path and make sure excel is not still running in the background after it is closed.
Can someone make it easy for me?
Thanks
Release the COM objects when completed...
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
# declare the application object
var xl = new Excel.Application();
# open a file
var wb = xl.Workbooks.Open("some_file.xlsx");
# close the file
wb.Close();
# close the application and release resources
xl.Quit();
#release the COM objects created as a final step:
Marshal.ReleaseComObject(wb);
Marshal.ReleaseComObject(xl);
Semi pseudo-code:
using Excel = Microsoft.Office.Interop.Excel;
# declare the application object
Excel.Application xl = new Excel.Application();
# open a file
Excel.Workbook wb = xl.Workbooks.Open("some_file.xlsx");
# do stuff ....
# close the file
wb.Close();
# close the application and release resources
xl.Quit();
I'm using VS2010 + Office Interop 2007 to attempt to get a few specific spreadsheet names from an Excel spreadsheet with 5-6 pages. All I am doing from there is saving those few spreadsheets I need in a tab delimited text file for further processing. So for the three spreadsheet names I get, each one will have its own tab delimited text file.
I can save a file as tab delimited just fine through Interop, but that's assuming I know what the given page name is. I have been informed that each page name will not follow a strict naming convention, but I can account for multiple names like "RCP", "rcp", "Recipient", etc when looking for a desired name.
My question is, can I get all spreadsheet page names in some sort of index so I may iterate through them and try to find the three names I need? That would be so much nicer than trying to grab "RCP", "rcp", "Recipient" pages via a bajillion try/catches.
I'm close, because I can get the COUNT of pages in an Excel spreadsheet via the following:
Excel.Application excelApp = new Excel.Application(); // Creates a new Excel Application
excelApp.Visible = true; // Makes Excel visible to the user.
// The following code opens an existing workbook
string workbookPath = path;
Excel.Workbook excelWorkbook = null;
try
{
excelWorkbook = excelApp.Workbooks.Open(workbookPath, 0,
false, 5, "", "", false, Excel.XlPlatform.xlWindows, "", true,
false, 0, true, false, false);
}
catch
{
//Create a new workbook if the existing workbook failed to open.
excelWorkbook = excelApp.Workbooks.Add();
}
// The following gets the Worksheets collection
Excel.Sheets excelSheets = excelWorkbook.Worksheets;
Console.WriteLine(excelSheets.Count.ToString()); //dat count
Thank you for your time.
foreach ( Worksheet worksheet in excelWorkbook.Worksheets )
{
MessageBox.Show( worksheet.Name );
}
You could use a dictionary:
Dictionary<string, Worksheet> dict = new Dictionary<string, Worksheet>();
foreach ( Worksheet worksheet in excelWorkbook.Worksheets )
{
dict.Add( worksheet.Name, worksheet );
}
// accessing the desired worksheet in the dictionary
MessageBox.Show( dict[ "Sheet1" ].Name );
I am trying to an Add-in directly from C# so that when I open a workbook, and do a Workbook.Calculate() the UDF's (User Defined Functions) that are defined in an external addin correctly calculate in the worksheet. Currently, I am looping through each adding and simple setting:
AddIn.Installed = true
This does not work. C# does not load add-in at all, and I want to avoid using VBA. I want to open a workbook an excel workbook with the specific add in loaded, do a full calculated, and should have all values of the worksheet updated, including cells with UDF's.
Thanks for any help....
Some code:
Excel.Workbook wkbk = ExcelApp.ActiveWorkbook;
Excel.XlFixedFormatType paramExportFormat = Excel.XlFixedFormatType.xlTypePDF;
Excel.XlFixedFormatQuality paramExportQuality = Excel.XlFixedFormatQuality.xlQualityStandard;
bool paramOpenAfterPublish = false;
bool paramIncludeDocProps = true;
bool paramIgnorePrintAreas = true;
object paramFromPage = Type.Missing;
object paramToPage = Type.Missing;
ExcelApp.Visible = true;
//foreach (Excel.AddIn aiTemp in ExcelApp.AddIns)
//{
// if (aiTemp.Name.Contains(""))
// {
// aiTemp.Installed = false;
// aiTemp.Installed = true;
// }
//}
while (ExcelApp.CalculationState == Microsoft.Office.Interop.Excel.XlCalculationState.xlCalculating)
{
Thread.Sleep(50);
}
ExcelApp.CalculateFull();
var wksht = wkbk.ActiveSheet;
Excel.Range rng = ((Excel.Worksheet)wksht).get_Range("B1", "B1");
rng.Calculate();
//EnsureCalcFinished();
ExcelApp.Visible = false;
wkbk.ExportAsFixedFormat(Microsoft.Office.Interop.Excel.XlFixedFormatType.xlTypePDF, PathToDocument.Replace(".xlsx", ".pdf"), paramExportQuality, true, false, Type.Missing, Type.Missing, true,Type.Missing);
UPDATE:
I found a link with the method I use to register UDFs.
Ref: http://msdn.microsoft.com/en-us/library/ms173189(v=vs.80).aspx
In Excel, you need to go to Options -> Add-Ins => Excel Add-in (Go..) => automation = select the library and hit OK. Once you do this once, it'll be auto-loaded each time you open excel.
Here is the algorithm to load excel AddIns so that when you open excel workbook, a calculation will include UDF's defined in Add-in:
1)Initiliaze Excel Application
ExcelApp = new Excel.Application();
2)Load AddIns *
foreach (Excel.AddIn ai in ExcelApp.AddIns)
{
ai.Installed = false;
ai.Installed = true;
ExcelApp.Wait(50);
}
**The Key is to load add-ins before you open Excel Workbook.
3)Open Excel Workbook, which will trigger calculations
4)Set Calculation Mode to manual so that any changes in Interop do not trigger lengthy recalc
ExcelApp.Calculation = Microsoft.Office.Interop.Excel.XlCalculation.xlCalculationManual;
5)Perform any manipulations, and perform calc
ExcelApp.CalculateFull();
6)Dispose of Excel Objects appropriately
Hope this helps someone with a similar issue.. Ended up being a simple fix for a simple problem. Just remember to load add-ins before opening the workbook. Otherwise, opening an excel workbook with UDF's dependent on AddIn will fail.