I have created an Excel VSTO Addin which will show a message box with yes, no and cancel as button options on the close event of Current document.
I have opened 2 excel documents to edit. After I complete my edit I try to close one of them, when I click on document close button my message box will appear.
If I click on "No" then all the changes should be discarded and the document should be closed. Other documents should not be closed.
This is the code I used on Don't save action
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
this.Application.WorkbookBeforeClose += Application_WorkbookBeforeClose;
}
private void Application_WorkbookBeforeClose(Excel.Workbook Wb, ref bool Cancel)
{
DialogResult result = MessageBox.Show("Do you want to save changes to " + Wb.Name + "?", "Microsoft Excel ", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);
switch (result)
{
case DialogResult.Yes:
Wb.Save();
break;
case DialogResult.No:
int count = this.Application.Workbooks.Count;
if(count > 0)
{
if (count == 1)
{
Excel.Application excel =Globals.ThisAddIn.Application;
Workbooks workbooks = excel.Workbooks;
foreach (Workbook wb in workbooks)
{
wb.Close(false, missing, missing);
}
workbooks = null;
excel.Quit();
excel = null;
}
else
{
Wb.Close(false, missing, missing);
}
}
break;
case DialogResult.Cancel:
Cancel = true;
break;
}
}
If morethan one excel document is opened for edit, then Excel vsto addin should close the particular excel docuemnent in which the close actions is performed and other documents should remain opened. My method closes the document but not closing the application.
How to close the Excel Application completely? my excel appear like this
The following code works for me, but it's important to keep in mind that the add-in technology wasn't really created with quitting the host application from within the add-in. So, "your mileage may vary".
Unlike the code in the question, this does not use Marshal.ReleaseComObject. This method is a "last resort" and forces an immediate release of the object. Once an object has been force-released the code can no longer work with it - but VSTO needs to do its internal clean-up. The method should only be used if the standard methods of releasing COM objects aren't doing the job. VSTO, in any case, as part of its "service" to the developer, takes care of standard releasing of COM objects properly declared and instantiated in the project. So it's enough, really, to set objects to null when they're no longer needed, which releases them for standard garbage collection. When VSTO goes out-of-process the objects will be released at the COM level, at the very latest.
private void btnQuitExcel_Click(object sender, RibbonControlEventArgs e)
{
Excel.Application xlApp = Globals.ThisAddIn.Application;
Excel.Workbooks wbs = xlApp.Workbooks;
int nrWbs = wbs.Count;
if (nrWbs > 0)
{
foreach (Excel.Workbook wb in wbs)
{
wb.Close(false, missing, missing);
}
}
wbs = null;
xlApp.Quit();
xlApp = null;
}
Already answered on Stack Overflow, see if it helps you
As outlined above, quitting Excel requires invoking the Quit method from within VBA code.
Related
I am trying to create a new instance of Excel using VBA using:
Set XlApp = New Excel.Application
The problem is that this new instance of Excel doesn't load all the addins that load when I open Excel normally...Is there anything in the Excel Application object for loading in all the user-specified addins?
I'm not trying to load a specific add-in, but rather make the new Excel application behave as though the user opened it themself, so I'm really looking for a list of all the user-selected add-ins that usually load when opening Excel.
I looked into this problem again, and the Application.Addins collection seems to have all the addins listed in the Tools->Addins menu, with a boolean value stating whether or not an addin is installed. So what seems to work for me now is to loop through all addins and if .Installed = true then I set .Installed to False and back to True, and that seems to properly load my addins.
Function ReloadXLAddins(TheXLApp As Excel.Application) As Boolean
Dim CurrAddin As Excel.AddIn
For Each CurrAddin In TheXLApp.AddIns
If CurrAddin.Installed Then
CurrAddin.Installed = False
CurrAddin.Installed = True
End If
Next CurrAddin
End Function
Using CreateObject("Excel.Application") would have the same result as using New Excel.Application, unfortunately.
You will have to load the Addins that you need individually by file path & name using the Application.Addins.Add(string fileName) method.
I'm leaving this answer here for anyone else who ran into this problem, but using JavaScript.
A little background... In my company we have a 3rd party web app that used JavaScript to launch Excel and generate a spreadsheet on the fly. We also have an Excel add-in that overrides the behavior of the Save button. The add-in gives you the option of saving the file locally or in our online document management system.
After we upgraded to Windows 7 and Office 2010, we noticed a problem with our spreadsheet-generating web app. When JavaScript generated a spreadsheet in Excel, suddenly the Save button no longer worked. You would click save and nothing happened.
Using the other answers here I was able to construct a solution in JavaScript. Essentially we would create the Excel Application object in memory, then reload a specific add-in to get our save button behavior back. Here's a simplified version of our fix:
function GenerateSpreadsheet()
{
var ExcelApp = getExcel();
if (ExcelApp == null){ return; }
reloadAddIn(ExcelApp);
ExcelApp.WorkBooks.Add;
ExcelApp.Visible = true;
sheet = ExcelApp.ActiveSheet;
var now = new Date();
ExcelApp.Cells(1,1).value = 'This is an auto-generated spreadsheet, created using Javascript and ActiveX in Internet Explorer';
ExcelApp.ActiveSheet.Columns("A:IV").EntireColumn.AutoFit;
ExcelApp.ActiveSheet.Rows("1:65536").EntireRow.AutoFit;
ExcelApp.ActiveSheet.Range("A1").Select;
ExcelApp = null;
}
function getExcel() {
try {
return new ActiveXObject("Excel.Application");
} catch(e) {
alert("Unable to open Excel. Please check your security settings.");
return null;
}
}
function reloadAddIn(ExcelApp) {
// Fixes problem with save button not working in Excel,
// by reloading the add-in responsible for the custom save button behavior
try {
ExcelApp.AddIns2.Item("AddInName").Installed = false;
ExcelApp.AddIns2.Item("AddInName").Installed = true;
} catch (e) { }
}
I need to automatize the following operation:
Open a Excel file at a scheduled time
(I configured its data connection so that the data automatically gets
updated)
Save a Copy of that file, WITHOUT including the data connection.
That report is sent to the customer and therefore can't possible include the query code.
The opening, updating and saving as a copy is not a problem and I will do it with a scripting tool that creates a Windows exe-file that then can be launched at the time I schedule it in Windows TaskScheduler.
But how can I manage to eliminate the data connection?
Regard,
Martin
Use a Workbook_Open event, which runs when the file is opened. Then use the scripting tool to open the file and the VBA should run automatically.
If you are using Excel Interop, you can use this code
using Excel = Microsoft.Office.Interop.Excel;
Excel.Application app = new Excel.Application();
app.DisplayAlerts = false;
Excel.Workbook wb = app.Workbooks.Open(filepath);
int count_conn = wb.Connections.Count;
if (count_conn > 0)
{
for (int i = 1; i <= wb.Connections.Count; i++)
{
wb.Connections[i].Delete();
i = i - 1;
}
count_conn = wb.Connections.Count;
wb.Save(); // Save workbook
}
wb.Save();
wb.Close();
app.Quit();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Marshal.ReleaseComObject(wb);
Marshal.ReleaseComObject(app);
}
I'm trying to create an Excel table and then insert it into a Word document using a C# Word Add-In. I've created a brand new Word 2010 Add-In and referenced the Microsoft.Office.Interop.Excel. As a quick test, I try to create a new Excel.Worksheet and populate it with a few values. I then insert it into the word document using the InsertDatabase method:
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
Excel.Worksheet testWrkSht = new Excel.Worksheet();
for(int i = 1; i < 5; i++)
{
testWrkSht.Range["A" + i.ToString()].Value = i ^ (i + 1);
}
Word.Document curDoc = this.Application.ActiveDocument;
curDoc.Paragraphs[1].Range.InsertDatabase(testWrkSht);
}
My problem is that when I try to execute this, I get the following error:
An exception of type 'System.InvalidCastException' occurred in
MyCustomAddIn.dll but was not handled in user code
Additional information: Unable to cast COM object of type
'Microsoft.Office.Interop.Excel.WorksheetClass' to interface type
'Microsoft.Office.Interop.Excel._Worksheet'. This operation failed
because the QueryInterface call on the COM component for the interface
with IID '{000208D8-0000-0000-C000-000000000046}' failed due to the
following error: The interface is unknown. (Exception from HRESULT:
0x800706B5).
How do I create an Excel spreadsheet table, and insert it into the Word Doc?
Since you're creating a Word Add-In, you'll need to open another instance of Excel, and then create the Excel Worksheet. Here's a quick example:
Excel.Application xlApp = new Excel.Application();
if (xlApp == null)
{
Console.WriteLine("Excel could not be started. Check that your office installation and project references are correct.");
return;
}
xlApp.Visible = true;
Excel.Workbook wb = xlApp.Workbooks.Add(Excel.XlWBATemplate.xlWBATWorksheet);
Excel.Worksheet ws = (Excel.Worksheet)wb.Worksheets[1];
if (ws == null)
{
Console.WriteLine("Worksheet could not be created. Check that you office installation and project references are correct.");
}
for(int i = 1; i < 5; i++)
{
ws.Range["A" + i.ToString()].Value = i * (i + 1);
}
wb.SaveAs(Filename: "C:\\temp\\test.xlsx");
This also assumes that you've added the appropriate using statement: using Excel = Microsoft.Office.Interop.Excel; as well as added a reference to the Excel Interop.
In my winforms app interacting with Excel through the com interop,
I'm trying to attach to an existing Excel process if there is one. Getting the object seems to work well, but if the Excel application is minimized (which is quite likely in my use case), I don't manage to restore the window and bring it to the front.
I've tried the following statements:
try
app = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
catch (Exception) { /* ignore */ }
if (app == null)
{
app = new Excel.Application();
app.Visible = true;
}
if (app.ActiveWindow.WindowState == Excel.XlWindowState.xlMinimized)
app.ActiveWindow.WindowState = Excel.XlWindowState.xlNormal;
wb = ...
wb.Activate();
None of these had any effect. How can I achieve that?
(Please Note: My problem relates to the case when there is an existing instance, so the "Visible = true" is not necessary and this thread does not apply.)
You want app.WindowState = xlNormal as app.ActiveWindow is the current sheet not the application instances main window.
I am trying to create a new instance of Excel using VBA using:
Set XlApp = New Excel.Application
The problem is that this new instance of Excel doesn't load all the addins that load when I open Excel normally...Is there anything in the Excel Application object for loading in all the user-specified addins?
I'm not trying to load a specific add-in, but rather make the new Excel application behave as though the user opened it themself, so I'm really looking for a list of all the user-selected add-ins that usually load when opening Excel.
I looked into this problem again, and the Application.Addins collection seems to have all the addins listed in the Tools->Addins menu, with a boolean value stating whether or not an addin is installed. So what seems to work for me now is to loop through all addins and if .Installed = true then I set .Installed to False and back to True, and that seems to properly load my addins.
Function ReloadXLAddins(TheXLApp As Excel.Application) As Boolean
Dim CurrAddin As Excel.AddIn
For Each CurrAddin In TheXLApp.AddIns
If CurrAddin.Installed Then
CurrAddin.Installed = False
CurrAddin.Installed = True
End If
Next CurrAddin
End Function
Using CreateObject("Excel.Application") would have the same result as using New Excel.Application, unfortunately.
You will have to load the Addins that you need individually by file path & name using the Application.Addins.Add(string fileName) method.
I'm leaving this answer here for anyone else who ran into this problem, but using JavaScript.
A little background... In my company we have a 3rd party web app that used JavaScript to launch Excel and generate a spreadsheet on the fly. We also have an Excel add-in that overrides the behavior of the Save button. The add-in gives you the option of saving the file locally or in our online document management system.
After we upgraded to Windows 7 and Office 2010, we noticed a problem with our spreadsheet-generating web app. When JavaScript generated a spreadsheet in Excel, suddenly the Save button no longer worked. You would click save and nothing happened.
Using the other answers here I was able to construct a solution in JavaScript. Essentially we would create the Excel Application object in memory, then reload a specific add-in to get our save button behavior back. Here's a simplified version of our fix:
function GenerateSpreadsheet()
{
var ExcelApp = getExcel();
if (ExcelApp == null){ return; }
reloadAddIn(ExcelApp);
ExcelApp.WorkBooks.Add;
ExcelApp.Visible = true;
sheet = ExcelApp.ActiveSheet;
var now = new Date();
ExcelApp.Cells(1,1).value = 'This is an auto-generated spreadsheet, created using Javascript and ActiveX in Internet Explorer';
ExcelApp.ActiveSheet.Columns("A:IV").EntireColumn.AutoFit;
ExcelApp.ActiveSheet.Rows("1:65536").EntireRow.AutoFit;
ExcelApp.ActiveSheet.Range("A1").Select;
ExcelApp = null;
}
function getExcel() {
try {
return new ActiveXObject("Excel.Application");
} catch(e) {
alert("Unable to open Excel. Please check your security settings.");
return null;
}
}
function reloadAddIn(ExcelApp) {
// Fixes problem with save button not working in Excel,
// by reloading the add-in responsible for the custom save button behavior
try {
ExcelApp.AddIns2.Item("AddInName").Installed = false;
ExcelApp.AddIns2.Item("AddInName").Installed = true;
} catch (e) { }
}