I can create an instance of Excel using:
Microsoft.Office.Interop.Excel.Application gXlApp = new Microsoft.Office.Interop.Excel.Application();
gXlWb= gXlApp.Workbooks.Add(Missing.Value);
gXlApp.Visible = true;
gXlApp.DisplayAlerts = false;
BUT is there a way to "point" gXlApp at an instance of Excel that is already open?
Currently I have to start Excel from c# then open the workbook and run my code.
Related
This question already has answers here:
How do I save an XLSM file as an XLSX file without prompting the user about lost data? [duplicate]
(1 answer)
Save a *.xlsm file as *.xlsx and suppress the pop-up
(1 answer)
Closed 13 days ago.
This post was edited and submitted for review 13 days ago.
I have a C# program that runs a macro existing inside an xlsm file and after this macro has finished its operations, I would like to save this xlsm as .xlsx file. This is the code that runs and saves the macro file as xlsx:
void RunMacro(string macroFilename, string xlsxFilePath)
{
Excel.Application app = new Excel.Application();
Excel.Workbook workbook;
workbook = app.Workbooks.Open(macroFilename);
app.Visible = true;
app.Run("Main");
workbook.SaveAs(xlsxFilePath, Excel.XlFileFormat.xlOpenXMLWorkbook);
app.Workbooks.Close();
app.Quit();
}
Now, the issue is that in the line workbook.SaveAs(), I will get a prompt like this from Excel:
So how can I make it programatically that "Yes" is the default option here and this prompt is automatically closed without needing to click on anything?
EDIT:
The following threads (linked as the reason for closing this question) are not a solution:
How do I save an XLSM file as an XLSX file without prompting the user about lost data?
Save a *.xlsm file as *.xlsx and suppress the pop-up
Basically, there are two proposed solutions in these threads:
Set application.DisplayAlerts = false and call workbook.SaveAs(xlsxFilePath, Excel.XlFileFormat.xlOpenXMLWorkbook);
This still results in a prompt coming up where it is necessary to select 'Yes'. Here is my code:
void RunMacro(string macroFilename, string xlsxFilePath)
{
Excel.Application app = new Excel.Application();
Excel.Workbook workbook;
workbook = app.Workbooks.Open(macroFilename);
app.Visible = true;
app.DisplayAlerts = false;
app.Run("Main");
workbook.SaveAs(xlsxFilePath,Excel.XlFileFormat.xlOpenXMLWorkbook);
app.Workbooks.Close();
app.Quit();
}
Use Workbook.SaveCopyAs(xlsxFilePath)
This method call does circumvent the Excel prompt, but the xlsx file that it produces is corrupted:
Here is the code:
void RunMacro(string macroFilename, string xlsxFilePath)
{
Excel.Application app = new Excel.Application();
Excel.Workbook workbook;
workbook = app.Workbooks.Open(macroFilename);
app.Visible = true;
app.Run("Main");
workbook.SaveCopyAs(xlsxFilePath);
app.Workbooks.Close();
app.Quit();
}
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.
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.
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.
I've been writing an application in C# which creates Custom Document properties in an Excel spreadsheet, I have a function for this which takes in a Workbook Object...
However, actually getting the current Workbook object is proving to be quite annoying, I am using ExcelDNA to add functionality, however, I can't seem to pass my function a valid Workbook COM object.
If you need to find the activeworkbook with C#, if you are using Office Interop, you can try this kind of code:
(Workbook)Globals.ThisAddIn.Application.ActiveWorkbook;
[Source]
This is the way I am currently doing it it seems to work really well
using Excel = Microsoft.Office.Interop.Excel;
Then you get active workbook
//Gets Excel and gets Activeworkbook and worksheet
Excel.Application oXL;
Excel.Workbook oWB;
Excel.Worksheet oSheet;
oXL = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
oXL.Visible = true;
oWB = (Excel.Workbook)oXL.ActiveWorkbook;
docProps = oWB.CustomDocumentProperties
Then I would try what you have and see how it works
Hope this helps
As #Govert explained above in his comment:
using Excel = Microsoft.Office.Interop.Excel;
using ExcelDna.Integration;
// Get the correct application instance
Excel.Application xlapp = (Excel.Application)ExcelDnaUtil.Application;
// Get active workbook
Excel.Workbook wbook = xlapp.ActiveWorkbook;
GetActiveObject() looks in the Running Object Table (ROT) and gives you the last Excel instance opened which may not corresponding with top Z order excel window.
Loop through the Z order and find the matching workbook.
See this link: -
https://social.msdn.microsoft.com/Forums/office/en-US/060000d8-a899-49bf-a965-0576dee958d4/how-to-get-active-application?forum=exceldev