I am writing an Excel Add-in. Following is my code
private void ThisAddInStartup(object sender, EventArgs e)
{
Excel.Sheets sheets = Application.ActiveWorkbook.Sheets;
_worksheet = (from Excel.Worksheet sheet in sheets where sheet.Name.Contains(SheetName) select sheet).FirstOrDefault();
Application.SheetChange += ApplicationSheetChange;
}
When I debug, everything works great. But When I open an excel file directly from my hard drive then I am getting Application.ActiveWorkbook as null. Can anybody help me to understand this.
I want to start my add-in as when an excel file opens. Basically my add-in is tracking change in excel sheet of workbook and doing some required action.
If it matters, I am using Office 2007, Visual Studio 2012. I am able to run the solution after changing the project file and replacing Office 14 part with 12.
I assume you mean ThisAddIn_Startup and instead of ThisAddInStartup. If not then that is probably a problem.
It is recommended that you don't try to access a document inside the ThisAddin_Startup method. This is because Office doesn't always have a document ready when this method is run so you could run into some strange behavior. Instead, hook into an event that fires when the user opens a document and run your code there. It should look something like this (Note: I haven't tested this code but it should work):
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
// Hook into the workbook open event
this.Application.WorkbookOpen += new AppEvents_WorkbookOpenEventHandler(WorkWithWorkbook);
}
private void WorkWithWorkbook(Microsoft.Office.Interop.Excel.Workbook workbook)
{
// Workbook has been opened. Do stuff here.
}
Check out the MSDN article on writing Application-Level addins. Specifically pay attention to the part that talks about accessing a document when the application starts.
http://msdn.microsoft.com/en-us/library/vstudio/bb157876.aspx
Related
I have a problem with development of a Office 365 Outlook Addin (Desktop).
I need to modify certain properties on a MailItem opened with a custom form ( Form designed in Outlook, exported as OFS file and imported in to Visual Studio AddIn project) but the call of method 'Save' on MailItem object
doesn't working, "Saved" property remain to "false" and when i close the inspector, Outlook prompt to save current item. No exception or error message raised on 'Save' call.
But if i try to call 'Save' to the same MailItem in the AddIn body, the message is saved.
I tried to write a simple test "addin" and i obtained the same result, but i can't understand this behaviour.
NB: with previous version of Outlook i haven't this issue.
Any idea?
Thanks so much!
Currently using VS2017, C#, .NET Framework 4.5, Interop library version 15.0
// ADD-IN BODY
private Outlook.Inspectors inspectors;
public static MailItem CurrentMailItem;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
inspectors = this.Application.Inspectors;
inspectors.NewInspector += Inspectors_NewInspector;
}
private void Inspectors_NewInspector(Inspector Inspector)
{
if (Inspector.CurrentItem is MailItem)
{
MailItem item = (MailItem)Inspector.CurrentItem;
item.MessageClass = "IPM.Note.MyReader";
item.Save();
bool saved = item.Saved;
Marshal.ReleaseComObject(item);
item = null;
}
}
// CUSTOM FORM:
private void FormRegion2_FormRegionShowing(object sender, System.EventArgs e)
{
// from this.OutlookItem
MailItem item = this.OutlookItem as MailItem;
item.Save();
bool saved = item.Saved; // <== SAVED=FALSE!
// from global variable (static)
ThisAddin.CurrentMailItem.Save();
saved = ThisAddin.CurrentMailItem.Saved; // <=== SAVED=FALSE!!!!
}
It seems you are using wrong event NewInspector to modify the message class. Have a look at this thread
I think it's a problem with the specific custom form that i've created, or a compatibility problem with Outlook 2016 (the same form working with Outlook 2013)
Steps to the resolution:
Create a new form for reader inspector with Outlook 20016.
Import new Form to Visual Studio 2017 project (there are some problem on import: it's necessary to add some registry key to specify Office installation path)
([see]https://social.msdn.microsoft.com/Forums/vstudio/en-US/3688eec8-2215-482c-ba5f-73f516ad26b8/unable-to-import-outlook-2016-form-region-ofs-into-visual-studio-2015-with-error-the?forum=vsto)
The new form is working and now i can modify and save mail item.
It's not the definitive solution, because now i must recreate a form with Outlook 2016 and i'm not sure that it's working with previous version of Office.
Moreover, the designer of Outlook 2016 have some problem with font sizeā¦ i can't change font size to '8' for any label present in the form.
I have a weird problem where Excel is behaving differently on my development machine and a testing machine.
In my add-in, I've turned off ScreenUpdating in several places for long running processes. On my machine this works fine. On the testing machine, Excel sets ScreenUpdating = true as soon as I write to a cell.
The following code demonstrates the issue for me.
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
Microsoft.Office.Interop.Excel.Application excel = Globals.ThisAddIn.Application;
MessageBox.Show(excel.ScreenUpdating.ToString());
excel.ScreenUpdating = false;
MessageBox.Show(excel.ScreenUpdating.ToString());
Workbook workbook = Globals.ThisAddIn.Application.ActiveWorkbook;
Worksheet w = (Worksheet)workbook.Worksheets[1];
((Range)w.Cells[1, 1]).Value = "Test";
MessageBox.Show(excel.ScreenUpdating.ToString());
}
On my machine, opening Excel gives three message boxes saying
"True", "False", "False".
On the test machine they say
"True", "False" and "True".
I've also stepped through with a remote debugger and watched the ScreenUpdating property change immediately after the cell value is set. Further, this isn't the only thing that resets ScreenUpdating. Adding or removing a Worksheet or Workbook will also do this.
The Excel version on each system is the same (14.0.6112.5000 (32-bit)).
What could be causing this? How can I fix it so that Excel respects my settings?
I am experincing the same problem with ScreenUpdating (and other settings) being reset to true by the Bloomberg add-in with VSTO add-in. Their support are working on a solution but in the meanwhile the following solution works ok:
By hiding each sheet when interacting with its cells the screen won't update and you'll get the performance benefits. Make sure to not try to hide the last sheet as it will raise an error. Not sure if this is suitable for your project but it is a workable solution for mine.
Here is some example code in VB.NET to hide a sheet:
' Create a book with a single worksheet
Dim Book As Excel.Workbook
Book = Globals.ThisAddIn.Application.Workbooks.Add(Excel.XlWBATemplate.xlWBATWorksheet)
'% Create sheet variable
Dim Sheet As Excel.Worksheet
Sheet = TryCast(Book.ActiveSheet, Excel.Worksheet)
' Visible
Sheet.Visible = Excel.XlSheetVisibility.xlSheetVisible
' Hidden but user able to show
Sheet.Visible = Excel.XlSheetVisibility.xlSheetHidden
' Hidden for user as well
Sheet.Visible = Excel.XlSheetVisibility.xlSheetVeryHidden
Other addins in Excel can interfere with that single global setting.
It is for that reason you are supposed to save the current ScreenUpdating state to a local variable before, and restore it after, each use.
Ignore the changing of that setting in the ThisAddIn_Startup event (as you would not normally do your work there anyway).
If an add-in is interfering with your ScreenUpdating somehow, you can stop them form doing it by disabling events temporarily. using EnableEvents. It is possible that this will break the functionality of that addon, but it worked fine for my needs.
In fact, I have a C# application that is runned.
When it's launched, it runs an excel instance and save it to a variable :
excelApp = new Excel.Application();
Then I cycle through each of the excel's addins to find my own created added :
private void getAddin()
{
const string addinName = "myAddInName";
foreach (Office.COMAddIn addin in excelApp.COMAddIns)
if (addin.Description.ToUpper().Contains(addinName.ToUpper()))
{
myAddin = addin;
return;
}
}
The problem is that, it may happens that my plugin is in the deactivated elements list. (Due to some crash)
Then I must go to (on excel's frame) :
File >Options >AddIns >Manage >Deactivated elements >Achieve >"myAddin" >Activate
to get my addin working again (after excel's restart)...
I tried using an addin's property to reactivate it but may app crashes again in that case.
myAddin.Connect = loadAddin;
Someone has an idea on how to resolve it / auto-reactivate a disabled plugin using C# ?
This should help
http://msdn.microsoft.com/en-us/library/aa662931(v=office.11).aspx
I believe you need to do
if(!myAddin.Connect)
{
myAddin.Connect =true;
}
I'd like to create an Excel Add In. But I want it to have a special behavior.
Then problem is that the Excel Add In I developed stays within Excel. Even when I run a normal Excel instance from Windows...
So what I want, to be more precise, is to have an Excel add in that will only appear in the Excel's ribbon when launched by my own C#_made application.
How should I do that ?
The behavior would be :
Run my C# application
My C# application calls a new Excel's instance
My C# application adds a new tab (and its elements) to the ribbon of this Excel's instance
My C# application adds actions binded to the tab's elements
Excel's instance is being closed > Remove all added components, functions, methods, ...
Close my C# appliclation
Here's a nice tutorial for you: http://www.add-in-express.com/free-addins/net-excel-addin.php
Edit:
Have you considered just disabling the addin, then reenabling it whenever you launch the app with a server that runs in the background and when excel is closed, disables the addin?
Here's some unload code I found here:
private void UnloadBadAddins(bool unloadAddin)
{
const string badAddin = "iManage Excel2000 integration (Ver 1.3)";
foreach(Office.COMAddIn addin in this.ExcelApp.COMAddIns)
{
if (addin.Description.ToUpper().Contains(badAddin.ToUpper()))
{
if (addin.Connect == unloadAddin)
{
addin.Connect = !unloadAddin;
return;
}
}
}
}
I have found the following two properties on the Microsoft.Office.Interop.Excel.Application class:
var excel = new Application();
excel.AddIns
excel.AddIns2
Maybe these can help you programmatically add/remove addins during your application run?
I know that I can display a PDF file in my c# executable (not web app) with:
private AxAcroPDFLib.AxAcroPDF axAcroPDF1;
axAcroPDF1.LoadFile(#"somefile.pdf");
axAcroPDF1.Show();
But that is the regular pdf viewer like in the browser. I don't want that. I want full Adobe Standard or Professional functionality in my C# application using the Adobe controls. For example, if I use the code above, it loads in the C# app and I can see the adobe toolbar (print, save, etc.) But it is useless to me because I need things like save which cannot be done with the activex viewer above. Specifically, you cannot save, just as you cannot within the broswer.
So, I referenced the acrobat.dll and am trying to use:
Acrobat.AcroAVDocClass _acroDoc = new Acrobat.AcroAVDocClass();
Acrobat.AcroApp _myAdobe = new Acrobat.AcroApp();
Acrobat.AcroPDDoc _pdDoc = null;
_acroDoc.Open(myPath, "test");
pdDoc = (Acrobat.AcroPDDoc)(_acroDoc.GetPDDoc());
_acroDoc.SetViewMode(2);
_myAdobe.Show();
It opens adobe acrobat but it opens it outside of my c# application. I need it to open in my c# application like the activex library does. Can it be done with these libraries?
If I cannot open it in my c# application I would like to be able to "hold" my c# app tied to it so the c# app knows when I close the adobe app. At least that way I'd have some measure of control. This means I would hit open, the adobe app opens. I close the adobe app, my C# app is aware of this and loads the newly changed doc with the activex library (because I don't need change ability anymore, just displaying.)
I have the full versions of adobe acrobat installed on my computer. It is not the reader.
Thank you for any help.
edit:
There is an example in vb in the adobe acrobat sdk. I believe it is called activeview.
you can check out ABCpdf. I dont know if it has this capability but we have used it for several of our apps
Using a webbrowser control would be an option to display the content.
IText# may help you out.
You can create PDF's and I believe you can use it to read and modify them.
As for displaying in the app..... I am not sure how to display them with iText or if it is possible (have not tried this yet), sorry. iText does let you convert to RTF which may be one approach.
Best option is to write a listener which tells your calling code when Adobe.exe is no longer running. Something like the following (with tweaks for your uses) should work:
public void Open(string myPath)
{
Acrobat.AcroAVDocClass _acroDoc = new Acrobat.AcroAVDocClass();
Acrobat.AcroApp _myAdobe = new Acrobat.AcroApp();
Acrobat.AcroPDDoc _pdDoc = null;
_acroDoc.Open(myPath, "test");
_pdDoc = (Acrobat.AcroPDDoc) (_acroDoc.GetPDDoc());
_acroDoc.SetViewMode(2);
_myAdobe.Show();
NotifyAdobeClosed += new EventHandler(Monitor_NotifyAdobeClosed);
MonitorAdobe();
}
private void Monitor_NotifyAdobeClosed(object sender, EventArgs e)
{
NotifyAdobeClosed -= Monitor_NotifyAdobeClosed;
//Do whatever it is you want to do when adobe is closed.
}
private void MonitorAdobe()
{
while(true)
{
var adcount = (from p in Process.GetProcesses()
where p.ProcessName.ToLower() == "acrobat"
select p).Count();
if (adcount == 0)
{
OnNotifyAdobeClosed();
break;
}
}
}
public event EventHandler NotifyAdobeClosed;
public void OnNotifyAdobeClosed()
{
if (NotifyAdobeClosed != null)
NotifyAdobeClosed(this, null);
}