Determining which Visual Studio context menu was selected? - visual-studio-2012

I'm writing a VS2012 add-in, adding a command to Build Explorer context menu (see related question). The command gets added to 2 different context menus:
Build Explorer
Team Explorer, Builds page, My Builds section
When my one callback is called, how do I know which of these it is?
I tried get the focused control (using P/Invoke as this question suggests). However, it gets me a Tabs container for (1), and null for (2). I could try to cast the control to the tabbed container, but that sounds pretty bad...
Any better alternative?

My new/other idea - it is similar to yours:
You should try to monitor which window was activated lastly.
If you create an eventhandler for your command, then you may be able to check which window is active when your command fired. A simple evenent handler for a command:
void cmdEvents_BeforeExecute( string guid, int ID, object customIn, object customOut, ref bool cancelDefault )
{
Window2 teamExplorer = _applicationObject.Windows.Item("Team Explorer") as Window2;
if (_applicationObject.ActiveWindow.Caption == teamExplorer.Caption)
{
//You are called from Team Explorer
}
else
{
//Somewhere else
}
}
And the way you can subscribe:
static _dispCommandEvents_BeforeExecuteEventHandler _myHandler;
static CommandEvents _cmdEvents;
public void OnConnection(...)
{
Command command = ...; // Init your command
int ID = command.ID;
string GUID = command.Guid;
CommandEvents _cmdEvents = _applicationObject.Events.get_CommandEvents(GUID, ID);
_myHandler = new _dispCommandEvents_BeforeExecuteEventHandler(cmdEvents_BeforeExecute);
_cmdEvents.BeforeExecute += _myHandler;
}
You may find a better way to identify the window(s) by GUID. You should keep at least _cmdEvents as static because when it will be desroyed, your event handler could vanish (least for internal commands).
In OnDisconnection you should unsubscribe.

Reworked by the comment, and founded links:
As the menu item is shown every place it seems there is no way to distinct between them from an Add-In, you should add two command and distinct them by their context.
The way instead of converting the Add-In to a VS-Package MZ-Tools HOWTO: Controlling the state of command in a Visual Studio add-in, try MZ-Tools HOWTO: Use the IVsMonitorSelection ... you can also get it from an Add-In.
But:
Neither the AddNamedCommand nor the QueryStatus methods honor the
invisible state: the button that must be invisible ...
remains disabled rather than invisible.
I think this makes it impossible to do it from an Add-In on a suitable way, but maybe you can check the contexts.
Other way you could get further, if you try to migrate your command/menu into a VSPackage and create a custom UIContext for the menu items or find a suitable predefined one. I have no access to a Studio enhanced with Build Explorer so I can't try it.
The following discussion is about custom contexts for vs-packages:
http://davedewinter.com/2008/04/05/dynamic-menu-commands-in-visual-studio-packages-part-3/
Sadly the links are broken from the post, and I can't reach Part 1. and Part 2. which is about the discussion of the problem from the beginning.
But there is no guarantee you can create a context which suits you.
Only context ID I found for Team Explorer is the guidTeamProjectCmdUIContext.
It is placed at vsshilds.h in Visual Studio 2010 SDK, vsshell*.h are also contain several others.
MSDN: Vsct files to define command, menus, ect. from packages.
Condition attribute for items:
http://msdn.microsoft.com/en-us/library/bb491718.aspx
http://msdn.microsoft.com/en-us/library/bb166515.aspx
MSDN: VisibilityItem element for commands and toolbars.
VisibilityItem element determines the static visibility of commands and toolbars.
... After the VSPackage is loaded, Visual Studio expects command visibility to be determined by the VSPackage rather than the VisibilityItem.
And finally about predefined Context Guids:
http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.shell.interop.uicontextguids80.aspx
http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.shell.interop.uicontextguids.aspx

Related

Show or Hide a VSTO Addin Ribbon

My goal is to simply offer my addin if Office application is launched with a certain argument.
Unfortunately, I could not find anything to help me do this. I have tried to use the Office Application Load Addin swtich /lc:Addin.dll with no success. One option I entertained was to create all of the Office addin registry entries upon time of wish to launch addin however this seemed extremely clumsy and way to much overhead. Also, the deal breaker for me was requiring registry creation elevated privileges in order to initialize the addin.
I decided to have my addin not do much of anything at startup unless a certain environment variable exists.
In order to do it this way I need to either set the ribbon to non-visible by default and show the Ribbon upon discovering the env variable. Or the opposite have the ribbon visible by default and hide the ribbon upon discovering env variable.
Things I have tried
Setting ribbon's tab Globals.Ribbons.MyRibbon.MyTab.visible = false.
Invalidating the Ribbon Globals.Ribbons.MyRibbon.RibbbonUi.Invalidate().
Invalidating the tab after setting visible to false Globals.Ribbons.MyRibbon.RibbbonUi.InvalidateControl(tabCtrlId).
The things tried dont include the dozens of thing to try to only load addin in certain circumstances.
I figured out a solution.
after digging into the base class AddinBase I discovered some methods available for me to override.
So I overrode the CreateRibbonExtensibilityObject method.
protected override IRibbonExtensibility CreateRibbonExtensibilityObject( )
{
if( Environment.GetCommandLineArgs( ).ToList( ).FirstOrDefault( a => a.ToLower( ).Contains( "/launchmyaddin" ) ) != null )
{
return null;
}
return base.CreateRibbonExtensibilityObject( );
}
What this does is prevent the ribbon from even being created if my switch is present and if it is present then I just pass off to the base class implementation in order to have the Addin create my ribbon like normal.
Also, CreateRibbonExtensibilityObject() returns an object that has a GetCustomUI( ribbonXml ) so we can create our custom ribbon from xml.
This gives us more power.
My solution only needed to show/hide a ribbon once only at startup. I did think about how this might be toggled on and off so I went poking around for other members I could override.
I believe you can override the CreateRibbonObjects( ) member which I think will get called upon every time the invalidate of a ribbon is called. Here you may be able to remove the item from the collection the base class returns that represents your ribbon you wish to hide.
If you use custom tab(s) (this is, ControlIdType=Custom) you may set visibility via:
foreach (var tab in Globals.Ribbons.Ribbon1.Tabs)
{
tab.Visible = false;
}

How to locate event handlers for OK and Help button in mfc?

I am new to MFC. In the project I am working on the dialogs are created in resource file(.rc).
In that there are OK button(id ID_OK) and Help button (id ID_Help). I am not able to find the event handlers for these two buttons. There are other buttons where the event handlers mapped are easily found. If someone teach me how to find those event handlers it would be very helpful.
And how can I find the functions which get called on clicking of the particular button by debugging in visual studio?
Thank you.
Double click the button (shown in rc) opened in Resource View in Visual Studio and you will be automatically placed by Studio where the Event handler is located in your code.
If this does not work, then probably delete the Button with ID's ID_OK and ID_Help in your resource view and again add it to the resource using different ID and then try to generate the event handler by double-clicking those buttons in resource view. This is because sometimes the value of ID's conflict with other ID values and hence Studio is not able to generate the Event-handler for you in that case.
Buttons don't have direct event handlers as in other frameworks (like in C#, WinForms etc). You must use message-maps in MFC.
ID_OK maps to virtual function CDialog::OnOK, you can just write your virtual function implementation. Framework will call it for you. You can also handle this message with WM_COMMAND message entry.
There is no standard resource ID as ID_Help - it is always capital, and has to be always in caps! No one is stopping you from using small letters, though - it for consistency and better readability.
Instead of fiddling with resource files (.RC and resource.h), mapping the same with your dialog class and things like that. I suggest you to go, and learn, without resource file. Start with drawing in frame (circles, filled-triangles whatever). Learn and know why virtual function are there for some messages, and message-maps for other (most) messages.
My two cents.

State driven menuitem in Visual Studio 2012 extension

I am writing a Visual Studio 2012 extension that defines several sub-menus to go in two existing Visual Studio context menus. The sub-menu items appear to work correctly except for one thing:
Until the first menu item in my package is clicked, the state of each menu item is its default state depending on its definition in the VSCT file. That works fine for menu items that are always enabled, but some menu items should be enabled or disabled based on certain changing conditions. After the package is sited, their states are set correctly, but how can I get the states to be set correctly before the first item is clicked?
There is no default state that works in my solution. The conditions might be true or false the first time my menus appear.
If you have a solution for this, or know where this has been addressed in a tutorial somewhere, I would appreciate your help.
I finally discovered the answer to my question at MSDN in an article called How to: Autoload a VSPackage. The "trick" is to set the ProvideAutoLoadAttribute on the package class that's created for the project. Here is the declaration for one of the projects I am working on:
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
[ProvideMenuResource("Menus.ctmenu", 1)]
[ProvideAutoLoad("{f1536ef8-92ec-443c-9ed7-fdadf150da82}")]
[Guid(GuidList.guidXamlHelpmeetPkgString)]
public sealed class XamlHelpmeetPackage : Package
{ ...
The third line is all that I added to make the otherwise working extension load early rather than on demand.

Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED)): ActiveX and C# Console Application

So, I am playing around with ActiveX and C# and ways how both of them can work together. the thing is I have hit the wall right in the beginning with mentioned error. Steps I have followed:
In VS2010 I selected MFC ActiveX Control project. Then I added a method "SHORT Multiply( SHORT a, SHORT b);" by clicking the Add method option in the menu that pops when you right click _DProjectname under ProjectnameLib in solution explorer. The code for the method is as follows:
SHORT CSampleProgramActivex01Ctrl::Multiply(SHORT a, SHORT b)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: Add your dispatch handler code here
return ( a * b);
}
Now I have created a simple C# console application that references the generated COM file and when I try to use the method, the application stops with the above mentioned error. I have searched the error on the internet but no clear solution is mentioned. Any help appreciated. If you guys want clarification, let me know.
I don't know whether this is considered as solving the problem or not but I found a workaround:
First instead of C# console application, I created C# windows form application. After creating the form, I have added the whole ocx as component in the toolbox. You do this by right-clicking the Toolbox types in Toolbox menu. In the new menu, you click Choose Items. This pops up new menu and in that select the COM tab and in that check your COM component and the COM component will be added to the Toolbox menu. Now drag and drop the component on the menu and you should be good to go.
This seems to be workaround that everybody is following. Not neat but that is the norm I think.
look at here: How to use an OLE control as an automation server in Visual C++
http://support.microsoft.com/kb/146120/en-us

Eclipse RCP: How to configure the Perspective Menu?

I need to have total control of the perspective menu.
I already hacked into the platform to disable the CONTEXT menu:
private void disablePerspectiveToolbarMenu() {
PerspectiveBarManager perspectiveBarManager =
((WorkbenchWindow) PlatformUI.getWorkbench().getActiveWorkbenchWindow()).getPerspectiveBar();
if (perspectiveBarManager!=null){
ToolBar toolBar = perspectiveBarManager.getControl();
Listener[] listeners = toolBar.getListeners(SWT.MenuDetect);
if (listeners != null){
for (Listener listener : listeners){
toolBar.removeListener(SWT.MenuDetect, listener);
}
}
}
}
But i need also to control the default contents of the PERSPECTIVE MENU. There is one option that is always present that gives access to a Perspective List Shell. I need to remove that option from the menu.
It's a shame that the perspective menu is totally out of user control. I just need to have the perspectives added to the menu, and nothing more!
Thanks.
There are 3 potential options to get rid of Other:
Set the
org.eclipse.ui.IWorkbenchPreferenceConstants.SHOW_OTHER_IN_PERSPECTIVE_MENU
preference to false in your RCP app. This can be done by including a plugin_customization.ini file with your product definition.
Patch the workbench in your RCP app.
Have a look at
org.eclipse.ui.internal.PerspectiveBarNewContributionItem
and
org.eclipse.ui.actions.ContributionItemFactory.PERSPECTIVES_SHORTLIST
Don't include the default
perspective bar in your RCP app.
Instead, create a perspective bar
using org.eclipse.ui.menus, a
toolbar, and the openPerspective
command.
I did some research and the solution did not work as I expected it. Finally I found my mistake.
To set the property in the plugin_customization.ini I tried:
org.eclipse.ui.IWorkbenchPreferenceConstants.SHOW_OTHER_IN_PERSPECTIVE_MENU=false
but this is not the correct notation!!! Please see the correct solution I added finally to the plugin_customization.xml
org.eclipse.ui/SHOW_OTHER_IN_PERSPECTIVE_MENU=false
So the name of the interface or the class specifying the property ist not part of the notation!

Resources