Programmatically assign hotkeys to VSPackage menu commands - c#

I am developing a new version of a Visual Studio extension. In the old version, the hotkeys were stored in the registry and I would like to import these settings into the new version of the software.
The new version uses .vsct format for defining menu commands and you can assign the hotkeys in the .vsct file. However, I can't use this mechanism, as I would like to import the user settings from the registry, whiles the .vsct is a static description.
When my VSPackage is initialized, I can read the old hotkeys from the registry, but I have problems assigning them to my menu commands defined in the .vsct file. I can get a hold on the OleMenuCommand interface and OleMenuCommandService, but they have no property where they can accept key bindings.
How one can assign hotkeys to menu commands programmatically?
A clunky workaround would be that the installer imports the hotkeys, writes them into the .vsct file, compiles the file and puts the .cto into the MyPackage.Resources.dll during the installation. But I'd rather not resort to this...

Though I define my commands through the .vsct file, I still can access them via the EnvDTE.Command interface.
// The commandGuid has to be the same GUID you use in the .vsct file, HOWEVER, you have to include the braces here
Command command = dte.Commands.Item(commandGuid, commandId);
command.Bindings = new object[] { "Global::Ctrl+Alt+Shift+1" };
It works. It is saved and remembered the next time Visual Studio starts up, so there is no need to import the old hotkeys every time.

Since I'm not allowed to comment [despite my 50 years of systems-level programming experience, including 3 books for MS Press :( ], I have to ask this way for Shakaron to post some more of his code. I added a short tree of menu commands to the VS 2015 Tools menu (1-4-1 elements). An enumeration of dte.Commands didn't show any of them. Calling Commands.Item with a string (or an "object" to which I'd assigned a string) containing the GUID, both with and without {}, generated an invalid argument exception.
So, either the EnvDTE80 interface is incredibly fragile, the documentation is wildly wrong, or else Shakaron's solution has some more magic that we haven't seen yet. And I was so hopeful that this would be the last piece of my puzzle...

Answering Shakaron's questions:
I used the .vsct file to add 1 menu with 3 commands and 1 submenu, which in turn had 1 command.
Calling Commands.Item with a guid and an index argument caused an apparently identical invalid argument exception. I was able to enumerate the collection, but my commands were not in the set.
I also couldn't compile your code for the right-hand-side of the Bindings assignment. But, of course, I didn't get that far because I couldn't find the command item in the first place.
There has to be a version dependency at work here. I don't doubt that your code worked a year ago, but I ran into the problems I described using a fresh-out-of-the-virtual-box copy of VS 2015 running on Win 10.

Related

How to correctly react on file change

I'm writing a Visual Studio editor plugin. I'd like the editor to behave similarly to other editors: if the edited file changes outside the IDE, I want the proper dialog window to be displayed and the document reloaded (if needed).
The IVsPersistDocData interface contains methods IsDocDataReloadable and ReloadDocData, but during debugging, they were never called in this scenario.
There is a combination of IVsFileChangeEx and IVsFileChangeEvents interfaces, but reaction to changing files outside the IDE seems to be so generic, that I guess I shouldn't need to manually monitor the edited file. Or should I?
It seems, that there actually is no automatic mechanism for doing that and using IVsFileChangeEx and IVsFileChangeEvents seems to be the only solution.
http://blogs.msdn.com/b/dr._ex/archive/2005/11/01/487721.aspx
http://msdn.microsoft.com/en-us/library/Microsoft.VisualStudio.Shell.Interop.IVsFileChangeEx.aspx

Refresh start menu icons in Windows 8

I have an application that works weirdly: the setup process copies the files to a temp folder, then checks a few things, and if everything is ok, moves the files to the final folder.
The problem is that the installer creates the shortcuts before the files are moved.
The result is that on the start menu (the one with the tiles), the icon is the "default sortcut" one.
I have tried to force the refresh of the system using this link (broadcast a WM_SETTINGCHANGE message) but it doesn't seem to work for the Windows 8 start menu.
Even rebooting the OS doesn't seem to refresh the icon, the only thing that works is to reinstall the soft on top of itself.
How can I force the icons refresh for the Win8 start menu ?
Thanks
First off, you don't tell us why your install process needs to work the way that it does. I agree that's weird, but I assume you have a good reason for doing it that way. If not, I suggest starting there and fixing the installer rather than putting band-aids on individual problems. You're bound to run into other problems later, and the root fix is bound to be much simpler and easier to maintain than a bunch of band-aids.
Anyway, if you must go down this path… The reason that broadcasting a WM_SETTINGCHANGE message doesn't work is because this doesn't have anything to do with icons. Those are managed separately by Explorer and don't get rebuilt unless you delete its icon cache. That, naturally, prompts it to rebuild it. It's a common troubleshooting technique for end users, but it's not something you want to do programmatically. Talk about an ugly hack. And altering the global state to solve a local problem.
Besides, if rebooting the OS doesn't work, you know it's not as simple as you make it sound in your question: a property in need of a refresh. The reason that reinstalling on top of the existing installation works is because when the shortcut gets created in the beginning, its target executable already exists in the expected place (put there by the previous installation) with a valid icon.
What I recommend doing is writing some code to change the icon of the existing shortcut. Make sure that you execute it after you've copied the executable file to its final destination. The method that allows you to do that is IShellLink::SetIconLocation, which takes two parameters: a path to the icon (this would be the path to your executable file), and the index of the icon (this would probably be 0 assuming that the icon you want is the first and only one contained in the executable).
Of course, in order to call SetIconLocation, you're going to have to obtain an object representing your shortcut that implements IShellLink. This is a COM interface, which I don't believe is wrapped anywhere by the .NET Framework. General information on creating shortcuts from C# is available in the answers to this question. More specifically, there's a link to this wrapper class that you can use to do most of the dirty work. I don't think it contains a method for setting/changing the icon, but that can be trivially added.
Alternatively, you can get at these same properties using the Windows Scripting Host (WSH) wrapper, WshShortcut. It has an IconLocation property that works much the same way except that it takes only a single string argument, with the index delimited from the path by a comma: myApp.exe, 0. It's not particularly well documented (best I can find), but to get an existing shortcut, you just use the CreateShortcut method and specify the path to the existing shortcut. For example:
public void SetShortcutIcon(string shortcutPath, string iconPath, int iconIndex)
{
// Note: no error checking is performed for the parameters!
// This is not production-ready code!
// If a shortcut does not exist at the specified path, you should
// create a new one instead.
// If iconPath does not specify a valid executable file, you should
// set a default icon or perhaps abort.
IWshRuntimeLibrary.WshShell wsh = new IWshRuntimeLibrary.WshShell();
IWshRuntimeLibrary.IWshShortcut shortcut = wsh.CreateShortcut(shortcutPath);
shortcut.IconLocation = String.Format("{0}, {1}", iconPath, iconIndex);
shortcut.Save();
}
Note that in order for the above code to compile, you will also need to add a reference to the Windows Script Host Object Model to your application. To do this, right-click on the "References" folder in the Solution Explorer, click the "COM" tab, and find "Windows Script Host Object Model" in the list.
I just tested this and it works; the effect is instant.

Visual Studio : When and why a class file name change will automatically update references to that class

Sometimes when I'm using Visual Studio and I alter the name of the file containing a code element (i.e. a class, interface) I get a very helpful prompt that offers to automatically update all references/uses of that code element to the new file name.
And other times I don't.
In all cases I'm referring to when the code element file name matches the code elements type name.
Why does this sometimes occur and sometimes not?
I gather it has something to do with either a predefined link or VS's ability to real time resolve dependencies.
I have played around with this however and while in all cases VS can helpfully find all dependencies/uses of/to a code element using the context menu options, it doesn't always offer the prompt if I change the file name. So whats the secret?
It works this way (at least from my experience):
the refactor is activated only when the file contains exactly one single class with the same file as the file. I.e. it doesn't work if there are more classes in the file, or even when there is an enum, or a struct.

Debug mode works. Release mode generates ERRORs galore!

I have a solution that uses a native .DLL library that is wrapped by a .NET .DLL with a C# GUI.
All my plumbing works just fine in Debug mode. The moment I try going to Release mode, I get a whole whack of error messages, largely to do with the .CPP files in the native library. Errors include the following:
definition of dllimport function not allowed
TRACE_DEBUG_METHOD_CALL: identifier not found
a lot of undeclared identifiers in my main .CPP file (eg: DLLAPI_Release: undeclared identifier)
I have to admit that the Properties configuration for a C/C++ project is overwhelming so I wonder if there is one or more simple settings somewhere that I simply need to modify.
ALSO, is there a book out there that is devoted to the project properties window in VS2010 specifically? I have a few books but none really spend anytime on what is obviously a very crucial component to serious app development.
I appreciate any assistance anyone can offer. Thanks!
This is not unlikely to happen when you made a bunch of setting changes but didn't also make them for the Release build. Easy to forget, the first time anyway. You can easily tell which settings were changed from the default, they are displayed in bold type. Step through the setting pages, flip back-and-forth with the Configuration combobox in the upper left corner.
About 15 minutes of your life, not counting the thinking time you need because the setting should be different for the Release build. Start another instance of Visual Studio with a dummy project to verify that.
Trying to compare the property pages can be a beating. My recommendation would be to open the property pages for your project, select the Debug configuration, and under "C/C++", select "Command Line" and copy the command line options into a text editor, then do the same for the Release configuration and see where they differ. You'll need to do the same for the "Linker" command line.
Some of the differences will be intentional (e.g. debug flags should be set for the Debug configuration), but you should be able to spot things that should be the same but are not.
Actually tracking down where the command line options are set can be a bit of a pain, especially if you are using property sheets to manage common properties between projects, but generally you should be able to track them down just by looking through the different options on the different pages.
As for a reference, the best reference is the actual compiler documentation on MSDN. There is a section containing all of the documented compiler options and one containing all of the documented linker options.
The property pages are just a GUI frontend for setting these various options. When you select one of the properties in the property pages, it should say in the help box at the bottom of the dialog which compiler options are used by that property.

Releasing WinForm Program Updates

I'd like to release some updates for a WinForm program, but to date I have simply released an all-new compile. People have to un-install the old version and install the new version.
EDIT: I'm using an auto-generated InstalWizard. It preserves my file strucutre and places the [PrimaryProgramOutput] in a particular directory. I forget what this is called.
I bet there's a way to get around this, but I don't know what it's called. As you may guess, searches for "updates" "new version" "install" and the other obvious things I've tried have generated an impressive number of irrelevant results. >_<
I suspect this process has a particular name, which should point me in the right direction, but if it doesn't please link to a tutorial or something.
I see from the tags you are using C#. Visual Studio can create Setup projects for these kind of tasks. The setup projects als contain a property RemovePreviousVersion, which will remove a previous version if the versioning of your setup is correct and the GUID of the application stays the same.
See this link for more information:
http://www.simple-talk.com/dotnet/visual-studio/updates-to-setup-projects/
ClickOnce deployment is a great solution most of the time...
You can deploy to the web and when ever your users start the application it will check for updates and automatically update the application if there is a new version available.
It can also be configured not to update automatically but only to notify the user that there is a new version available and allow the user to control the update process.

Categories