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?
Related
I am developing a simple Add-In for Outlook with C#. Now as I was testing the release, suddenly Outlook print an error message and disables my Add-In:
This add-in caused Outlook to start slowly. (1.594 seconds)
I am not sure what causes this. All I do Onload are these this:
Ribbon Button
I am using a single ribbon button which I initialize in my AddIn as follows:
protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
{
return new MyRibbonButton();
}
Ribbon Button constructor
The ribbon button initialize an object. So nothing special yet.
public MyRibbonButton()
{
this.guiSettings = new AppSettingsManager(root.localmachine, "GUI", false);
}
...
public AppSettingsManager(root type, string subpath, bool writable)
{
if (subpath != "")
{
this.PATH += #"\" + subpath;
}
this.type = type;
this.writable = writable;
}
Icon
In the same MyRibbonButton class I declare the icon I want to use for my button depending on a value in the registry.
public Bitmap imageSuper_GetNotifyImage(IRibbonControl control)
{
switch (guiSettings.GetValueInt32("Icon", 1))
{
case 1:
return Properties.Resources.icon1;
case 2:
return Properties.Resources.icon2;
case 3:
return Properties.Resources.icon3;
default:
return Properties.Resources.icon1;
}
}
As you can see I don't do anyting special except maybe the Registry Read in the last part. Do you think this causes Outlook to start slowly? If so, how can I optimize it.
You get penalized for loading the .Net system. There used to be a "warmup" registry key which could be used to force Outlook to load the right version of the .Net run-time without being penalized, but that key no longer works.
The only way I was able to work around that problem is to create a stub addin in Delphi (C++ would work just as well if not better) that did nothing but get loaded by Outlook (in about 20ms) and start a timer. When the timer fires (Outlook would be idle and not monitoring the addin), it would load the slave .Net addin using the IManagedAddin interface.
Before asking my question I would like to describe briefly background of my problem: I'm developing ms word COM addin on C# and I need to handle user's text selections. Now I'm able to catch selection event - it's look like
Microsoft.Interop.Word._Application app;
app = (Word._Application )Application; // Application object comes on addin's connection
app.Application.WindowSelectionChange+=
new Word.ApplicationEvents4_WindowSelectionChangeEventHandler(selChange);
///
void selChange(Word.Selection selection){
MessageBox.Show(selection.Text); // this is my problem, Text property is not available
}
// property Text doesn't exist,but documentation tells that it exists. I suspect, that this property is not available for ms word 2007 - in the documentation only 2003,2010 versions are mentioned. But how I can do something like selection.getSelectedText()? I tryed to play with selection.Rows, selection.Rows[0],selection.Words,selection.Words[0] - no success.
According to the documentation, the Selection.Text property should be available for Word 2007 as well. I made a small sample implementation of your case to test it, and I cannot make it fail on Word 2010 and 2013 at least:
var wordApplication = new Application() { Visible = true };
wordApplication.Documents.Add();
wordApplication.WindowSelectionChange += delegate(Selection mySelection) { Console.WriteLine(mySelection.Text); };
So, I suggest you check that you have included the right namespaces and that the Selection interface you are using are actually the one from the Microsoft.Office.Interop.Word namespace.
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 am trying to create a little helper application, one scenario is "file duplication finder". What I want to do is this:
I start my C# .NET app, it gives me an empty list.
Start the normal windows explorer, select a file in some folder
The C# app tells me stuff about this file (e.g. duplicates)
How can I monitor the currently selected file in the "normal" windows explorer instance. Do I have to start the instance using .NET to have a handle of the process. Do I need a handle, or is there some "global hook" I can monitor inside C#. Its a little bit like monitoring the clipboard, but not exactly the same...
Any help is appreciated (if you don't have code, just point me to the right interops, dlls or help pages :-) Thanks, Chris
EDIT 1 (current source, thanks to Mattias)
using SHDocVw;
using Shell32;
public static void ListExplorerWindows()
{
foreach (InternetExplorer ie in new ShellWindowsClass())
DebugExplorerInstance(ie);
}
public static void DebugExplorerInstance(InternetExplorer instance)
{
Debug.WriteLine("DebugExplorerInstance ".PadRight(30, '='));
Debug.WriteLine("FullName " + instance.FullName);
Debug.WriteLine("AdressBar " + instance.AddressBar);
var doc = instance.Document as IShellFolderViewDual ;
if (doc != null)
{
Debug.WriteLine(doc.Folder.Title);
foreach (FolderItem item in doc.SelectedItems())
{
Debug.WriteLine(item.Path);
}
}
}
You can do this with the shell automation interfaces. The basic process is to
Run Tlbimp on Shdocwv.dll and
Shell32.dll (or directly add a
reference from VS).
Create an
instance of the ShellWindows
collection and iterate. This will
contain both Windows Explorer and
Internet Explorer windows.
For
Windows Explorer windows, the
IWebBrowser2.Document property will
return a IShellFolderViewDual
reference.
The IShellFolderViewDual
has a SelectedItems method you can
query and an event for changes you
can handle.
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);
}