locked
Custom File Type Icons in Solution Explorer - Part 3 RRS feed

  • Question

  • I've already posted a couple of threads (one and two) on this.

    I have a custom editor for a file type hosted in Visual Studio. I want it to display with a custom icon in Solution Explorer.

    I can create an item template for it (or just change the ProvideEditorExtension attribute ProjectGuid to one of these), but the custom icon (<VSTemplate><TemplateData><Icon> element in vstemplate file) only shows up in the Add New file dialog, not the Solution Explorer.

    I know I could set the custom icon in a project system (or subtype/flavor), but I don't need a new project type. The tool I'm building targets an existing, widely used project type. I don't want users to have to create new projects using a different project type in the New Project dialog (and also migrate historical projects).

    Even better, it would be nice to let the users add the custom editor to a variety of existing project types.  I can create multiple instances of the ProvideEditorExtension attribute with different ProjectGuids (one for each of the targeted project types), but again the attribute only shows up in the Add New file dialog, not the file node in Solution Explorer.

    The options suggested so far in the previous 2 threads I submitted will not work partly due to difficulty with deployment.  I just need a simple VSIX deployment. The Visual Studio Icon Patcher requires Visual to be closed down to be applied.  Plus it replaces existing icons, not add new ones.

    Creating a project system/subtype/flavor seems to be the only possible option as discussed in this thread.  I went through this Walkthrough on project systems and successfully changed the icon of a file type in the Solution Explorer.  I modified the steps to work for a custom file icon instead of project icon.

    I also took a look at this project subtype sample which is only available for VS 2010.  I don't know why this sample is not available in the 2013 SDK samples (assuming they didn't bother creating a new one - it won't work in 2013).

    But again, apart from a project subtype/system having no VS 2013 samples, I don't want a new project type.  All I need is my custom editor files to show up using a different icon in the solution explorer.

    Seems like an obvious thing that anyone creating a custom editor would want to do.

    There may not be a workable solution to this, but I thought I'd bump it one more time anyway.  I might just have to live with the lame Notepad icon.

    • Edited by bulldog___ Monday, September 22, 2014 9:50 PM
    Sunday, September 21, 2014 12:11 AM

Answers

  • Hi Bulldog,

    The project type has a set number of icons that are associated with various file types. For file types the project system doesn't recognize, the project implementation will typically check the OS for an icon associated with the file extension, and then use that if one exists.

    Problem is, this would require a custom installer, as you'd need to register your extension's .ICO under the HKCR hive in the registry as detailed here:

       How to Assign a Custom Icon to a File Type

    Because .PKGDEF files can only place registry settings under the VS registry hive, you'll need to author a custom setup, such that your installer adds the requisite registry values described in the above article.

    Sincerely,


    Ed Dore

    Wednesday, September 24, 2014 5:00 AM
  • For reference, I am assuming it is not possible to get the easy extension update process from the Visual Studio Gallery if I go with a custom installer.

    Therefore I'm sticking with VSIX deployment for now and offering a separate executable for users to set up the icon if they wish.  This could be run from the extension as a separate process as administrator (if comfortable with that).

    The separate executable is a console app with app.manifest file containing the following to ensure runs as admin.

    <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

    The code is as follows.

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using Microsoft.Win32; namespace BismNormalizerIconSetup { class Program { [System.Runtime.InteropServices.DllImport("shell32.dll")] private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2); const string extension = ".XXXX"; static void Main(string[] args) { try { RegistryKey rk = Registry.ClassesRoot.OpenSubKey(extension + "\\DefaultIcon"); if (rk != null) { Console.WriteLine("Icon already set up in registry at HKEY_CLASSES_ROOT\\" + extension + ". No further action will be taken."); } else { //Should set up icon somewhere like program files. Should not register it pointing at extension directory in VS files because gets new folder for new version string iconTarget = "C:\MyIcon.ico"; //Set up icon in registry RegistryKey rkExt = Registry.ClassesRoot.CreateSubKey(extension, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.Volatile); RegistryKey rkIco = rkExt.CreateSubKey("DefaultIcon", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.Volatile); rkIco.SetValue("", iconTarget); //Clear icon cache SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero); Console.WriteLine("Set up of icon complete. Restart Visual Studio to see the icon in Solution Explorer."); } } catch (Exception exc) { Console.WriteLine("Exception occurred:"); Console.WriteLine(exc.Message); } finally { Console.WriteLine(); Console.WriteLine("Press any key to exit"); Console.ReadKey(); } } } }


    • Edited by bulldog___ Wednesday, October 15, 2014 8:45 PM
    • Marked as answer by bulldog___ Wednesday, October 15, 2014 8:52 PM
    Wednesday, October 15, 2014 8:38 PM

All replies

  • Hello,

    I'm trying to involve some other engineer in your case, since I'm unable to give you a solution which exactly meet your requirement. If there're any updates, we'll come back and follow up in your thread. This may take some time, so please be patient.

    Thanks for your understanding.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Monday, September 22, 2014 8:53 AM
  • Thanks.  I look forward to hearing from you/them.
    Monday, September 22, 2014 2:57 PM
  • Hi Bulldog,

    The project type has a set number of icons that are associated with various file types. For file types the project system doesn't recognize, the project implementation will typically check the OS for an icon associated with the file extension, and then use that if one exists.

    Problem is, this would require a custom installer, as you'd need to register your extension's .ICO under the HKCR hive in the registry as detailed here:

       How to Assign a Custom Icon to a File Type

    Because .PKGDEF files can only place registry settings under the VS registry hive, you'll need to author a custom setup, such that your installer adds the requisite registry values described in the above article.

    Sincerely,


    Ed Dore

    Wednesday, September 24, 2014 5:00 AM
  • Thank you for your help.

    The reason I need "simple VSIX deployment" is I want the users to get the easy extension update process from the Visual Studio Gallery by using "Extensions and Updates" > Updates.

    If I create a custom installer, do I lose this easy update process from the VS Gallery?

    Could I not just check if the icon is set up correctly in the package Initialize method, and if not, run some custom code to set up the registry settings? In this case I can stick with VSIX deployment and the auto-updates work.

    I have created a separate thread for this question: VSPackage Deployment: Custom Installer with VS Gallery Auto Updates

    • Edited by bulldog___ Wednesday, September 24, 2014 7:55 PM
    Wednesday, September 24, 2014 6:00 PM
  • For reference, I am assuming it is not possible to get the easy extension update process from the Visual Studio Gallery if I go with a custom installer.

    Therefore I'm sticking with VSIX deployment for now and offering a separate executable for users to set up the icon if they wish.  This could be run from the extension as a separate process as administrator (if comfortable with that).

    The separate executable is a console app with app.manifest file containing the following to ensure runs as admin.

    <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

    The code is as follows.

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using Microsoft.Win32; namespace BismNormalizerIconSetup { class Program { [System.Runtime.InteropServices.DllImport("shell32.dll")] private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2); const string extension = ".XXXX"; static void Main(string[] args) { try { RegistryKey rk = Registry.ClassesRoot.OpenSubKey(extension + "\\DefaultIcon"); if (rk != null) { Console.WriteLine("Icon already set up in registry at HKEY_CLASSES_ROOT\\" + extension + ". No further action will be taken."); } else { //Should set up icon somewhere like program files. Should not register it pointing at extension directory in VS files because gets new folder for new version string iconTarget = "C:\MyIcon.ico"; //Set up icon in registry RegistryKey rkExt = Registry.ClassesRoot.CreateSubKey(extension, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.Volatile); RegistryKey rkIco = rkExt.CreateSubKey("DefaultIcon", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.Volatile); rkIco.SetValue("", iconTarget); //Clear icon cache SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero); Console.WriteLine("Set up of icon complete. Restart Visual Studio to see the icon in Solution Explorer."); } } catch (Exception exc) { Console.WriteLine("Exception occurred:"); Console.WriteLine(exc.Message); } finally { Console.WriteLine(); Console.WriteLine("Press any key to exit"); Console.ReadKey(); } } } }


    • Edited by bulldog___ Wednesday, October 15, 2014 8:45 PM
    • Marked as answer by bulldog___ Wednesday, October 15, 2014 8:52 PM
    Wednesday, October 15, 2014 8:38 PM