I am confused about the implementation of the IRibbonUI interface that is exposed in the Outlook Object Model.
When the XML file for the either the Explorer or Inspector ribbon are written, we have to define which method will be responsible for loading the XML into Outlook.
Note: that this code was not originally written by me but I've been tasked to fix the solution..or at the least find a reason why this thing doesn't work as expected.
Anyways, the methods to set the ribbons are defined in the following methods: Ribbon_OnLoad and ERibbon_OnLoad
Public Sub Ribbon_OnLoad(ByVal Ribbon As Office.IRibbonUI)
m_Ribbon = Ribbon
End Sub
Public Sub ERibbon_OnLoad(ByVal Ribbon As Office.IRibbonUI)
m_ERibbon = Ribbon
End Sub
Now what I am confused is why the method for the Inspector never fires? When I step through the code and even when I open an inspector object, my global variable m_Ribbon is sometimes Nothing and vice versa for the m_ERibbon variable.
There have been times where m_ERibbon has been nothing and there has been times m_Ribbon has been nothing..I'm starting to think I may have deeply misunderstood how the Ribbon for Office works.
Now it becomes more intricate when I have to invoke the callbacks via the Invalidate method. I have an explorer wrapper and a inspector wrapper which invoke either m_ERibbon.Invalidate() or m_Ribbon.Invalidate() depending if the user is using the Explorer or Inspector.
What I do not understand is this:
Why doesn't Ribbon_OnLoad fire ALL the time, and why doesn't ERibbon_OnLoad fire all the time, despite the fact I've explictly set the onLoad method to fire these methods?
Why are there instances where m_ERibbon or m_Ribbon are Nothing?
From what I can tell is despite the Invalidate() method being invoked from the Explorer or the Inspector...the call to Invalidate() invokes ALL of the callbacks despite some callbacks being placed in the inspector and vice versa.
Have I understood this incorrectly?
EDIT I'm adding code for the GetCustomUI because this is where the markup is defined. Despite the respective XML markups being available for both the Explorer and the Inspector; the method Ribbon_OnLoad (for the Inspector) doesn't fire.
Function GetCustomUI(ByVal RibbonID As String) As String Implements Microsoft.Office.Core.IRibbonExtensibility.GetCustomUI
Select Case RibbonID
Case "Microsoft.Outlook.Mail.Read"
Return basRibbon.QFGetRibbonMailRead()
Case "Microsoft.Outlook.Explorer"
Return basRibbon.GetRibbonExplorerFolder()
Case Else
Return String.Empty
End Select
End Function
And a snippet of the XML markup is the following (note that this is for the Inspector):
sRibbonXML = "<customUI xmlns=""http://schemas.microsoft.com/office/2006/01/customui"" onLoad=""Ribbon_OnLoad"" >" & _
Snippet of the XML markup for the Explorer:
sRibbonXML = "<customUI xmlns=""http://schemas.microsoft.com/office/2009/07/customui"" onLoad=""ERibbon_OnLoad"" " & _
Microsoft Office applications call the GetCustomUI method to obtain an XML string that defines the user interface of your custom Ribbon.
public class Connect : Object, Extensibility.IDTExtensibility2, IRibbonExtensibility
...
public string GetCustomUI(string RibbonID)
{
StreamReader customUIReader = new System.IO.StreamReader("C:\\RibbonXSampleCS\\customUI.xml");
string customUIData = customUIReader.ReadToEnd();
return customUIData;
}
Note, sometimes you need to return the XML markup for different ribbonID values passed as an argument. In that case you will get the onLoad callback invoked (for inspectors too).
public string GetCustomUI(string ribbonID)
{
string ribbonXML = String.Empty;
if (ribbonID == "Microsoft.Outlook.Mail.Compose")
{
ribbonXML = GetResourceText("Trin_RibbonOutlookBasic.Ribbon1.xml");
}
return ribbonXML;
}
See Customizing a Ribbon for Outlook for more information.
You can read more about the Fluent UI (aka Ribbon UI) in the following series of articles in MSDN:
Customizing the 2007 Office Fluent Ribbon for Developers (Part 1 of 3)
Customizing the 2007 Office Fluent Ribbon for Developers (Part 2 of 3)
Customizing the 2007 Office Fluent Ribbon for Developers (Part 3 of 3)
Please remember that by default, if an VSTO add-in attempts to manipulate the Microsoft Office user interface (UI) and fails, no error message is displayed. However, you can configure Microsoft Office applications to display messages for errors that relate to the UI. You can use these messages to help determine why a custom Ribbon does not appear, or why a Ribbon appears but no controls appear. See How to: Show Add-in User Interface Errors for more information.
Related
I have created a working add-in for Outlook and now I try to add an image to a button. I've seen in many questions that you need to set the getImage="GetImage" property and provide a callback function for it, so I did:
public Bitmap GetImage(IRibbonControl ribbon)
However, with this method the add-in doesn't even load. I tried a couple of other signatures like
public stdole.IPictureDisp GetImage(Microsoft.Office.Core.IRibbonControl ribbon)
public Bitmap GetImage(Microsoft.Office.Core.IRibbonControl control)
public stdole.IPictureDisp GetImage(string idMso, int Width, int Height)
but none of them worked. What is the correct signature of this function?
The getImage callback's signature is listed below:
C#: IPictureDisp GetImage(IRibbonControl control)
-
VBA: Sub GetImage(control As IRibbonControl, ByRef image)
-
C++: HRESULT GetImage([in] IRibbonControl *pControl, [out, retval] IPictureDisp ** ppdispImage)
-
Visual Basic: Function GetImage(control as IRibbonControl) as IPictureDisp
Read more about the Fluent UI (aka Ribbon UI) in the following series of articles:
Customizing the 2007 Office Fluent Ribbon for Developers (Part 1 of 3)
Customizing the 2007 Office Fluent Ribbon for Developers (Part 2 of 3)
Customizing the 2007 Office Fluent Ribbon for Developers (Part 3 of 3)
I got it and I post a self-answer, maybe it helps someone someday...
In order to use the getImage callback you must not set the image property. It's either or.
I'm trying to develop a snippet in C # code that enables the "voting option" function of Outlook.
This code will be used by a platform called Blue Prism.
The "vote" function of Outlook is in the Microsoft.Office.Interop.Outlook namespace, so I need to import it using C#, but I dont have enough knowledge to develop this.
I tried to do something like this but it is giving an error.
Here is the code:
public class program {
[DllImport(#"C:\Program Files\Blue Prism Limited\Blue Prism Automate\Microsoft.Office.Interop.Outlook.dll", EntryPoint = "VotingOptions")]
public static extern string Outlook(uint type);
static void Main()
{
// Create the Outlook application.
Outlook.Application oApp = new Outlook.Application();
oApp.VotingOption = "Yes; No";
}
}
So, can someone help me?
The VotingOptions property belongs to the MailItem class , not Outlook Application. Voting options on messages are used to give message recipients a list of choices and to track their responses. To create voting options programmatically, set a string that is a semicolon-delimited list of values for the VotingOptions property of a MailItem object. The values for the VotingOptions property will appear under the Vote command in the Respond group in the ribbon of the received message.
private void OrderPizza()
{
Outlook.MailItem mail = (Outlook.MailItem)Application.CreateItem(
Outlook.OlItemType.olMailItem);
mail.VotingOptions = “Cheese; Mushroom; Sausage; Combo; Veg Combo;”
mail.Subject = “Pizza Order”;
mail.Display(false);
}
Also you may find the C# app automates Outlook (CSAutomateOutlook) sample project helpful, it shows how to automate Outlook in C#.
Com objects aren't accessed through DLLImport. They're accessed using references. From the sample Eugene linked:
Create a Console application and reference the Outlook Primary Interop Assembly (PIA). To reference the Outlook PIA, right-click the project file and click the "Add Reference..." button. In the Add Reference dialog, navigate to the .NET tab, find Microsoft.Office.Interop.Outlook 12.0.0.0 and click OK.
Now you'll have access to the Microsoft.Office.Interop.Outlook object.
If you are using Blue Prism then rather than having to specify DLL references you may also chose to go the GetObject or CreateObject way, you will be able to interact with Outlook just like Blue Prism does with Excel. The drawback of this approach is that you have to use VB.NET (unless I am mistaken) and that you will not be able to use text representation of enum values (so for OlItemType you will not be able to use olMailItem but only its numeric value, which is 0).
Please note that Blue Prism has released a new version recently (6.3) and with it a new VBO for interaction with Outlook. It's nothing revolutionary, but it may provide some insight.
It's me again :)
I making global Escape shortcut for application. Its implementation from global hook and send close message in DomainModelContext(main UserControl from scaffolding wizard). I trying bad way - use code-behind.
I use DockLayoutManager.DockController.Close(DockLayoutManager.ActiveDockItem)
for close tab, but its method close everything including LayoutPanel :(
How i do implement Close active document with tabbed and floating docs.
Under the document, I mean View inherited from SingleObjectViewModel or those that were manually undocked
The correct way to accomplish your task is to handle the CloseMessage at the View Model level (DomainModelContextViewModel, I believe).
At this level you can use the API of the IDocumentManagerService:
void OnCloseMessage() {
var activeDocument = DocumentManagerService.ActiveDocument;
if(activeDocument != null)
activeDocument.Close();
}
Note: the specific implementation of the IDocumentManagerService (TabbedDocumentUIService) should be registered within the DomainModelContextView.
I am looking for a way to have my extension check if the currently opened window in visual studio 2012 is one, where the user can write code (or any kind of text, really).
To check if the currently opened window has changed, I use
_DTE.Events.WindowEvents.WindowActivated.
This gives me the EnvDTE.Window that received the focus.
When I look at the properties of that window while debugging, and I look at EnvDTE.Window.Document.Type and it's value is "Text".
However, if I stop debugging and try to access the Document.Type property, it does not exist.
If I look for this property in the documentation of EnvDTE.Window.Document, its description says
Infrastructure. Microsoft Internal Use Only.
So now I am looking for any advice on how I could check if the currently active window is one, where I can write code (or anything else), or some other kind of document (like the solution properties for example).
Edit:
I also tried checking Window.Type and Window.Kind of the active window, but they just tell me that it's a document, not making any differentiation between a resource file, an image file or an actual source file, which is what I'm trying to find out.
Edit²:
The reason why I want to check if the current document is one where I can write code in, is because I want my extension to store information about some of those documents and I want to modify the right-click context menu based on the information I have stored, if any.
It is not a "real" answer, but you can follow status of VS GoTo command - it is available only for text editors:
bool isCodeWindow = IsCommandAvailable("Edit.GoTo");
private bool IsCommandAvailable(string commandName)
{
EnvDTE80.Commands2 commands = dte.Commands as EnvDTE80.Commands2;
if (commands == null)
return false;
EnvDTE.Command command = commands.Item(commandName, 0);
if (command == null)
return false;
return command.IsAvailable;
}
You can check to see if the document is a 'TextDocument'
bool isCodeWindow = dte.CurrentDocument.Object() is EnvDTE.TextDocument;
I've read several articles that tell you how to add text to the output window in visual studio from within an Add-On (specifically, a visual studio 2008 integration package, via the visual studio 2008 SDK 1.1), but no examples of how to read text from the output window. My goal is to parse text from the debug output window while debugging a certain application (TRACE output and possibly stdin/stdout). The IVsOutputWindowPane interface has no methods for reading in text from the output window. The documentation seems to imply that it is possible, but it doesn't provide an example:
http://msdn.microsoft.com/en-us/library/bb166236(VS.80).aspx
Quote: In addition, the OutputWindow and OutputWindowPane objects add some higher-level functionality to make it easier to enumerate the Output window panes and to retrieve text from the panes.
Preferably I'd like to be able to subscribe to an event that fires when a new line of text arrives, similar to a StreamReader's asynchronous reads.
It is possible, it is just a long winding path to get to it:
ServiceProvider -> IVsOutputWindow -> GetPane( debugwindow ) -> IVsUserData -> GetData( wpftextviewhost ) -> IWpfTextViewHost -> IWpfTextView -> TextBuffer -> Changed event.
Presuming you have a VS IServiceProvider from somewhere else (vsix extension/whatever, global service provider), and without any error checking, it looks like this:
IVsOutputWindow outWindow = ServiceProvider.GetService(typeof(SVsOutputWindow)) as IVsOutputWindow;
Guid debugPaneGuid = VSConstants.GUID_OutWindowDebugPane;
IVsOutputWindowPane pane;
outWindow.GetPane(ref debugPaneGuid, out pane);
// from here up you'll find in lots of other stackoverflow answers,
// the stuff from here down is interesting to this question
IVsUserData userData = (IVsUserData)pane;
object o;
Guid guidViewHost = DefGuidList.guidIWpfTextViewHost;
userData.GetData(ref guidViewHost, out o);
IWpfTextViewHost viewHost = (IWpfTextViewHost)o;
IWpfTextView textView = viewHost.TextView;
textView.TextBuffer.Changed += YourTextChangedHandlerHere;
Your text changed handler will then get called every time the output window gets more data. you won't necessarily get it line by line, but you'll probably more likely than not get big chunks you'll need to deal with on your own.
It is highly likely that some of the above did not even exist in VS in 2010. But it exists now!
The default behavior (when you don’t set the listener explicitly) of VS is to display trace massages in the debugger output window, which you appreciate if you want a simple solution and do no other actions with the massages.
Unfortunately this is not your case. So you have to define a trace listener to send (and store) your trace massages where you then will be able to read them. The trace listener could be a file (for example XML) or you can create a custom listener by deriving a class from the base class TraceListener if you don't want to bother yourself with an additional file.
I don't know that what you ask is possible. But, you can register your add-in as a debugger for your application so that you get the output the trace messages. These are typically routed to OutputDebugString, and can be captured as described in this article: http://www.drdobbs.com/showArticle.jhtml?articleID=184410719. It does not give you the normal output, only debug, but it does not depend on the technology of the debugged application.
The solution on this page selects the text in order to read it. I'm hoping there's a better way.
Automatically stop Visual C++ 2008 build at first compile error?
Private Sub OutputWindowEvents_OnPaneUpdated(ByVal pPane As OutputWindowPane) Handles OutputWindowEvents.PaneUpdated
pPane.TextDocument.Selection.SelectAll()
Dim Context As String = pPane.TextDocument.Selection.Text
pPane.TextDocument.Selection.EndOfDocument()
End Sub