I am writing a VSTO C# code that would copy the content of active projects in Visual Basic editor in any Office application and process it following some rules. The AddIn adds a button to the VBE toolbar and an event for a click.
When debugging, it works fine the first couple of times (between 8 and 12) I click the button but then it just stops responding to the clicks. Restarting the application does not help, but repeat debugging does (again, for the first 8 - 12 clicks).
I experimented with the code and found that it behaves this way whenever the code uses Regex, even something rather basic. Any ideas what may be going wrong?
This piece of code is for the illustration only. All it is supposed to do is to produce a message box "OK" after it applies Regex to each code module content. And so it does - for the first 8 to 12 times. After that, the button clicks produce no response whatsoever.
No error messages are shown, except when it is building the solution, among many lines it shows Exception thrown: 'System.Deployment.Application.DeploymentException' in System.Deployment.dll, which does not seem to affect the program during the first clicks.
using Office = Microsoft.Office.Core;
using VBA = Microsoft.Vbe.Interop;
using System.Text.RegularExpressions;
namespace CodeControl
{
public partial class ThisAddIn
{
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
AddButton();
}
public void AddButton()
{
Office.CommandBar cbr = Globals.ThisAddIn.Application.VBE.CommandBars["Edit"];
Office.CommandBarButton button = cbr.Controls.Add(Type: 1, Temporary: true).Control;
button.FaceId = 10;
button.Visible = true;
Globals.ThisAddIn.Application.VBE.Events.CommandBarEvents[button].Click +=
new VBA._dispCommandBarControlEvents_ClickEventHandler(DoWork);
}
void DoWork(object CommandBarControl, ref bool handled, ref bool CancelDefault)
{
foreach (VBA.VBComponent component in Globals.ThisAddIn.Application.VBE.ActiveVBProject.VBComponents)
{
VBA.CodeModule module = component.CodeModule;
if (module.CountOfLines < 4)
continue;
string text = module.Lines[1, module.CountOfLines];
foreach (string lineText in Regex.Split(text, #"(?:\r\n|\n|\r)"))
Console.WriteLine(lineText);
System.Windows.Forms.MessageBox.Show(module.Name);
}
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e){}
#region VSTO generated code
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}
Related
I'm writing Outlook VSTO add-in and I want to do size check before attachment add and if the file is too big I want to upload it to the cloud, so the code looks like:
public partial class ThisAddIn
{
private void ThisAddIn_Startup(object sender, EventArgs e)
{
Application.Inspectors.NewInspector += InspectorsOnNewInspector;
}
private void InspectorsOnNewInspector(Inspector inspector)
{
if (inspector.CurrentItem is MailItem mailItem)
{
mailItem.BeforeAttachmentAdd += MailItemOnBeforeAttachmentAdd;
}
}
private void MailItemOnBeforeAttachmentAdd(Attachment attachment, ref bool cancel)
{
// check and upload
cancel = true;
}
private void ThisAddIn_Shutdown(object sender, EventArgs e)
{
// Note: Outlook no longer raises this event. If you have code that
// must run when Outlook shuts down, see https://go.microsoft.com/fwlink/?LinkId=506785
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
[SuppressMessage("ReSharper", "ArrangeThisQualifier")]
[SuppressMessage("ReSharper", "RedundantDelegateCreation")]
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
The problem is that all works fine until the file exceeds the size limit configured in MS Exchange. When it happens I get a notification message and after clicking "OK" mailItem.BeforeAttachmentAdd event doesn't fire. How can I deal with it?
None of your event handlers will work for more than a few seconds - you are setting the event handler either on a temporary variable (created by the compiler) in case of Application.Inspectors.NewInspector or on a local variable (when you set mailItem.BeforeAttachmentAdd event handler).
The object raising the events must be alive - store these objects on the global (class) level to make sure they are not collected by the Garbage Collector.
Also, there is no particular / guaranteed order of events, but I would imagine Outlook would always get the first pick. Worst case, you can patch IDropTarget implementation of the Outlook window and provide your own implementation. Not much you can do if an attachment is being inserted from the Ribbon...
I am developing a VSTO application for PowerPoint using C#. The goal is to export the selected slide of the opened PowerPoint presentation to PNG file on user's computer every 5 seconds.
PowerPoint API provides the following way to export the slide:
(Slide)Application.ActiveWindow.View.Slide.Export("D:/path", "png")
However, every time this method is called, PowerPoint window freezes (maybe deactivates?) for a split second, and because of this any expanded menus get closed (for example, the menu opened by right-clicking on a slide, menu for inserting shapes, etc.)
I am looking for a way to avoid this. Is there a way to fix this issue when using Slide.Export method? Or maybe there are some alternatives to using it?
I tried using custom libraries like Aspose.Slides, and they can fix this issue, but cause an even worse one: they can't access the Presentation object presented by PowerPoint assembly, so in order to use them on your assembly, you would have to save a copy to the computer and open it, which is a bad solution in my case.
Any ideas on how to fix my issue will be very helpful.
Edit: to reproduce the issue, create a VSTO add-in project for PowerPoint and replace ThisAddIn with the following code:
public partial class ThisAddIn
{
public Form form = new Form
{
Opacity = 0.01,
Visible = false,
};
delegate void InvokeEventHandler();
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
form.Show();
var del = new InvokeEventHandler(() => Timer_Tick());
form.Invoke(del);
var timer = new System.Timers.Timer();
timer.Interval = 5000;
timer.Elapsed += (s, ea) => form.Invoke(del);
timer.Start();
}
private void Timer_Tick()
{
try
{
var slide = (Slide)Application.ActiveWindow.View.Slide;
slide.Export(Path.Combine(Path.GetTempPath(), "test"), "png");
}
catch
{
return;
}
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
When PowerPoint opens, right-click on a slide and wait for a couple of seconds. When timer ticks, the menu will be closed.
The specified graphics format must have an export filter registered in the Windows registry. You can specify either the registered extension or the registered filter name. Microsoft PowerPoint will first search for a matching extension in the registry. If no extension that matches the specified string is found, PowerPoint will look for a filter name that matches.
Try using the JPG file format instead:
With Application.ActivePresentation.Slides(3)
.Export "c:\my documents\Graphic Format\" & _
"Slide 3 of Annual Sales", "JPG"
End With
I having terrible when i execute the same method second time.i am not getting WPF screen, I don't know why?
refer my code
TestWindow Button click method(it is windows application project type) and i have removed STA thread in my
Main()
TestClass test;
private void button1_Click(object sender, EventArgs e)
{
test =TestClass.Instance; //singleton pattern
test.ShowScreen();
}
TestClass
public void ShowScreen()
{
var thread = new Thread(() =>
{
Explorer explorer = new Explorer();
explorer.Show();
explorer.Closed += (s, args) =>
explorer.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
Above the code working fine when i run 1st time. i can able view my explorer screen.
But the problem is when i close 1st screen and call once again the same method(test.ShowScreen();) the explorer screen not showing
Note : I have noticed If i didn't close the 1st window(instance) then i can able open many explorer screen. using the same code. If i closed the 1st window(instance) and i am unable open explorer screen and i am not getting any error message.
The issue is resolved Adding the following line in the TestClass Constructors
using SW = System.Windows;
private TestClass()
{
if (SW.Application.Current == null)
{
new SW.Application
{
ShutdownMode = SW.ShutdownMode.OnExplicitShutdown
};
}
}
I have developed a MS Word add-in and it has several buttons in the ribbon menu. The first button is a Toggle button and clicking it causes a task pane to load. The problem I have been experiencing is that if I have multiple instances of MS Word open and I click this toggle button in one of the instances, it automatically appears clicked in the other running instances of MS Word as well but the task pane appears to be loaded only in the instance where I had clicked the toggle button. I would like the toggle button to work independently in every instance of MS Word. I have tried several ways of doing this but haven't found a solution yet. I have experienced the same behavior for another add-in that I developed for MS PowerPoint.
Any help in this matter will be appreciated.
I have a ribbon designer (named rbcOfficeAddin) added to my add-in project and it has a toggle button named btnTaskPane. Below is the code:
public partial class rbcOfficeAddin
{
private void btnTaskPane_Click(object sender, RibbonControlEventArgs e)
{
if (this.btnTaskPane.Checked)
{ this.btnTaskPane.Label = "Hide Task Pane"; }
else { this.btnTaskPane.Label = "Show Hide Pane"; }
Globals.ThisAddIn.ShowHideActionPane(this.btnTaskPane.Checked);
}
}
The click handler of toggle button calls a method of ThisAddin as shown below:
public partial class ThisAddIn
{
private bool operationsPaneCreated = false;
public void ShowHideActionPane(bool flag)
{
try
{
if (!this.operationsPaneCreated)
{
this.CreateTaskPane();
this.operationsPaneCreated = true;
}
myCustomTaskPane.Visible = flag;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void CreateTaskPane()
{
//OperationsPane is a user control
oOperationsPane = new OperationsPane();
myCustomTaskPane = this.CustomTaskPanes.Add(oOperationsPane,
"Operations Pane");
myCustomTaskPane.DockPosition =
Office.MsoCTPDockPosition.msoCTPDockPositionFloating;
myCustomTaskPane.Height = 500;
myCustomTaskPane.Width = oOperationsPane.Width;
myCustomTaskPane.DockPosition =
Office.MsoCTPDockPosition.msoCTPDockPositionRight;
myCustomTaskPane.Width = 420;
myCustomTaskPane.Control.AutoScroll = true;
myCustomTaskPane.Visible = false;
myCustomTaskPane.VisibleChanged += myCustomTaskPane_VisibleChanged;
}
void myCustomTaskPane_VisibleChanged(object sender, EventArgs e)
{
try
{
if (!myCustomTaskPane.Visible && Globals.Ribbons.rbcOfficeAddin.btnTaskPane.Checked)
{
Globals.Ribbons.rbcOfficeAddin.btnTaskPane.Checked = false;
Globals.Ribbons.rbcOfficeAddin.btnTaskPane.Label = "Show Task Pane";
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
This same question was asked and answered on the MSDN forums. I'm copying/pasting the relevant information here, with attributions, from
https://social.msdn.microsoft.com/Forums/vstudio/en-US/1c3cab02-b231-4453-ae09-325e025606bf/in-a-vsto-ms-word-addin-a-ribbon-toggle-button-clicked-in-one-document-causes-it-to-be-clicked-in?forum=vsto
Answer from Starain chen Microsoft contingent staff, Moderator:
As far as I know, this is by design, for an instance with multiple
word documents, the same add-in will be in a domain, for example, a
variable is changed will be affect other word documents if they are in
the same instance. So, you need to deal with this scenario. (e.g. base
on document name)
Answer from Cindy Meister, MVP, Moderator:
The following article explains the approach. It's valid for Ribbon
customizations as well as just Custom Task Panes
https://msdn.microsoft.com/en-us/library/vstudio/bb608620
Debug versions (86, 64, ARM) all work fine, release versions build fine, but when they run all that happens is my app window opens and remains blank (white background). The only errors I see in the output are a whole bunch of:
...PDB file was not present when IL code was compiled to native.
I'm not sure if the missing .pdb files are the culprit - pretty sure they're not, cause they're just for debugging purposes right?
Anyways, this is the first UWP app I have tried to get ready for the Windows Store, and not completely sure if I have to do anything special like sign it to test release versions on my own computer?
Edit 1: Thank you #Alan for your suggestions, manually uninstalling the app sometimes gets me past the blank window to load the app bar, but then I am getting these errors when it doesn't hang on the splash screen:
Debugger Error 1,
Debugger Error 2
I have done nothing special to the splash screen, loaded all my visual assets using the built in tools in manifest, and have not modified App.xaml.cs from its default. Here is my Mainpage.cs:
using Sublist.Classes;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace Sublist
{
public sealed partial class MainPage : Page
{
const string TAG = "MainPage: ";
// for loading and saving user data and settings
public static DataHandler dataHandler;
public static MasterList<Entry> masterList;
//public static int listViewSelectedIndex = -1;
public MainPage()
{
this.InitializeComponent();
dataHandler = new DataHandler(this);
masterList = new MasterList<Entry>();
// load user data
if (dataHandler.userDataList != null)
masterList = dataHandler.userDataList;
masterList.UpdateListView(this);
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
dataHandler.LoadUserSettings();
}
private void AppBarAdd_Click(object sender, RoutedEventArgs e)
{
masterList.AddRow(this);
}
private void AppBarRemove_Click(object sender, RoutedEventArgs e)
{
if (!(mainListView.SelectedIndex < 0))
{
masterList.RemoveRow(this);
}
}
private void AppBarMoveDown_Click(object sender, RoutedEventArgs e)
{
}
private void AppBarMoveUp_Click(object sender, RoutedEventArgs e)
{
}
private void AppBarIndent_Click(object sender, RoutedEventArgs e)
{
// indent the row control if currently selected index is a list view item
if (-1 < mainListView.SelectedIndex && mainListView.SelectedIndex < mainListView.Items.Count)
{
// but don't allow more than one indent past above row's indent level
RowControl rc = (RowControl)mainListView.Items[mainListView.SelectedIndex];
int indexMinus1 = mainListView.SelectedIndex - 1;
if (-1 < indexMinus1 && rc.indentProp <= masterList[indexMinus1].indent)
{
rc.indentProp++;
}
}
// then update list view
masterList.UpdateListView(this);
}
private void AppBarUnindent_Click(object sender, RoutedEventArgs e)
{
// unindent the row control if currently selected index is a list view item
if (-1 < mainListView.SelectedIndex && mainListView.SelectedIndex < mainListView.Items.Count)
{
// but don't allow unindenting off left side of page
RowControl rc = (RowControl)mainListView.Items[mainListView.SelectedIndex];
if (rc.indentProp > 0)
{
rc.indentProp--;
}
}
// then update list view
masterList.UpdateListView(this);
}
public void AppBarShowCompl_Click(object sender, RoutedEventArgs e)
{
dataHandler.SaveUserSettings();
masterList.UpdateListView(this);
}
public void AppBarMarkAsCompleted_Click(object sender, RoutedEventArgs e)
{
// toggle hidden state of active entry
if (-1 < mainListView.SelectedIndex && mainListView.SelectedIndex < masterList.Count)
{
masterList[mainListView.SelectedIndex].completed = (masterList[mainListView.SelectedIndex].completed) ? false : true;
masterList.UpdateListView(this);
}
}
}
}
I have added the FileService and SettingsService classes from the opensource Template10 to the project.
The build setting "compile with .NET Native tool chain" was unchecked, I've tried deploying with it checked/unchecked for both debug/release versions, and now the debug version also often hangs on the splash screen? With it checked, I get a whole bunch of these errors as well:
'Sublist.exe' (Win32): Loaded 'C:\Windows\System32\biwinrt.dll'. Skipped loading symbols. Module is native, and native debugging is currently disabled.
I've tried downloading the server symbols with no success...
I found the hang happens at the following line in GetIfFileExitsAsync.
retval = await Windows.Storage.ApplicationData.Current.LocalFolder.GetFileAsync(key);
I made the following change in you code and it should work now.
In DataHandler's constructor, use Task.Run to initialize the userDataList.
public DataHandler(MainPage mp)
{
mainPage = mp;
settingsHelper = new SettingsHelper();
fileHelper = new FileHelper();
LoadUserSettings();
Task.Run(() =>
{
userDataList = LoadUserData();
});
Task.WaitAll();
}
I am still not sure why the .net native compile will make this issue, but will try to simplify the project and report it in MS internal channel.