Geeks With Blogs
Geekswithblogs

Sample download

In Part 1 of the series, we gave an introduction of writing Windows Shell extension in .NET Framework 4, and demonstrated a "skeleton" Context Menu Handler.

This article introduces the sample: Infotip Handler.

CSShellExtInfotipHandler:   Shell infotip handler (C#) 
VBShellExtInfotipHandler:   Shell infotip handler (VB.NET)
CppShellExtInfotipHandler: Shell infotip handler (C++)

An infotip handler is a shell extension handler that provides pop-up text when the user hovers the mouse pointer over the object. It is the most flexible way to customize infotips. The alternative way is to specify either a fixed string or a list of certain file properties to be displayed (See the Infotip Customization section in http://msdn.microsoft.com/en-us/library/cc144067.aspx)

Demo

Here is a quick demo of the infotip handler code sample.  After you successfully build the CSShellExtInfotipHandler sample project in Visual Studio 2010, you will get a DLL: CSShellExtInfotipHandler.dll. Run 'Visual Studio Command Prompt (2010)' (or 'Visual Studio x64 Win64 Command Prompt (2010)' if you are on a x64 operating system) in the Microsoft Visual Studio 2010 \ Visual Studio Tools menu as administrator. Navigate to the folder that contains the build result CSShellExtInfotipHandler.dll and enter the command:

    Regasm.exe CSShellExtInfotipHandler.dll /codebase

The infotip handler is registered successfully if the command prints:

    "Types registered successfully"

Find a .cs file in the Windows Explorer (e.g. FileInfotipExt.cs in the sample folder), and hover the mouse pointer over it. you will see an infotip with the text:

    File: <File path, e.g. D:\CSShellExtInfotipHandler\FileInfotipExt.cs>
    Lines: <Line number, e.g. 123 or N/A>
    - Infotip displayed by CSShellExtInfotipHandler

 To unregister the infotip handler, run the following command in the same Visual Studio 2010 command prompt.

    Regasm.exe CSShellExtInfotipHandler.dll /unregister

 

Implementation Details

A. Creating and configuring the project

In Visual Studio 2010, create a Visual C# / Windows / Class Library project named "CSShellExtInfotipHandler". Open the project properties, and in the Signing page, sign the assembly with a strong name key file.

-----------------------------------------------------------------------------

B. Implementing a basic Component Object Model (COM) DLL

Shell extension handlers are all in-process COM objects implemented as DLLs. Making a basic .NET COM component is very straightforward. You just need to define a 'public' class with ComVisible(true), use the Guid attribute to specify its CLSID, and explicitly implements certain COM interfaces. For example,

    [ClassInterface(ClassInterfaceType.None)]
    [Guid("B8D98AB4-376B-45D0-9CF6-8BF22A588989"), ComVisible(true)]
    public class SimpleObject : ISimpleObject
    {
        ... // Implements the interface
    }

You even do not need to implement IUnknown and class factory by yourself because .NET Framework handles them for you.

-----------------------------------------------------------------------------

C. Implementing the infotip handler and registering it for a certain file class

-----------
Implementing the infotip handler:

The FileInfotipExt.cs file defines an infotip handler. The infotip handler must implement the IQueryInfo interface to create text for the tooltip, and implement the IPersistFile interface for initialization.

    [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("00021500-0000-0000-c000-000000000046")]
    internal interface IQueryInfo
    {
        // The original signature of GetInfoTip is
        // HRESULT GetInfoTip(DWORD dwFlags, [out] PWSTR *ppwszTip);
        // According to the documentation, applications that implement this method
        // must allocate memory for ppwszTip by calling CoTaskMemAlloc. Calling
        // applications (the Shell in this case) calls CoTaskMemFree to free the
        // memory when it is no longer needed. Here, we set PreserveSig to false
        // (the default value in COM) to make the output parameter 'ppwszTip' the
        // return value. We also marshal the string return value as LPWStr. The
        // interop layer in CLR will call CoTaskMemAlloc to allocate memory and
        // marshal the .NET string to the memory.
        [return: MarshalAs(UnmanagedType.LPWStr)]
        string GetInfoTip(uint dwFlags);

        int GetInfoFlags();
    }

The IPersistFile interface is available in the System.Runtime.InteropServices.ComTypes namespace.
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.comtypes.ipersistfile.aspx
 
    [ClassInterface(ClassInterfaceType.None)]
    [Guid("B8D98AB4-376B-45D0-9CF6-8BF22A588989"), ComVisible(true)]
    public class FileInfotipExt : IPersistFile, IQueryInfo
    {
        #region IPersistFile Members

        public void GetClassID(out Guid pClassID)
        {
            ...
        }

        public void GetCurFile(out string ppszFileName)
        {
            ...
        }

        public int IsDirty()
        {
            ...
        }

        public void Load(string pszFileName, int dwMode)
        {
            ...
        }

        public void Save(string pszFileName, bool fRemember)
        {
            ...
        }

        public void SaveCompleted(string pszFileName)
        {
            ...
        }

        #endregion  


        #region IQueryInfo Members

        public string GetInfoTip(uint dwFlags)
        {
            ...
        }

        public int GetInfoFlags()
        {
            ...
        }

        #endregion
    }

When you write your own handler, you must create a new CLSID by using the "Create GUID" tool in the Tools menu for the shell extension class, and specify the value in the Guid attribute.

    ...
    [Guid("B8D98AB4-376B-45D0-9CF6-8BF22A588989"), ComVisible(true)]
    public class FileInfotipExt : ...


  1. Implementing IPersistFile

  The Shell queries the extension for IPersistFile and calls its Load method passing the file name of the item over which mouse is placed.   IPersistFile.Load opens the specified file and initializes the wanted data.   In this code sample, we save the absolute path of the file.

    public void Load(string pszFileName, int dwMode)
    {
        // pszFileName contains the absolute path of the file to be opened.
        this.selectedFile = pszFileName;
    }

  The rest methods of IPersistFile are not used by the Shell for infotip handlers, so we can simply make them blank or throw a NotImplementedException exception.

  2. Implementing IQueryInfo

  After IPersistFile is queried, the Shell queries the IQueryInfo interface and the GetInfoTip method is called. GetInfoTip returns a string containing the tip to display.

  In this code sample, the example infotip is composed of the file path and the count of text lines.

    // Prepare the text of the infotip. The example infotip is composed of
    // the file path and the count of code lines.
    int lineNum = 0;
    using (StreamReader reader = File.OpenText(this.selectedFile))
    {
        while (reader.ReadLine() != null)
        {
            lineNum++;
        }
    }

    return string.Format("File: {0}\nLines: {1}\n" +
        "- Infotip displayed by CSShellExtInfotipHandler",
        this.selectedFile, lineNum.ToString());

The IQueryInfo.GetInfoFlags method is not currently used. We simply throw a NotImplementedException exception in the method.

-----------
Registering the handler for a certain file class:

Infotip handlers can be associated with a file class. The handlers are registered by setting the default value of the following registry key to be the CLSID the handler class.

    HKEY_CLASSES_ROOT\<File Type>\shellex\{00021500-0000-0000-C000-000000000046}

The registration of the infotip handler is implemented in the Register method of FileInfotipExt. The ComRegisterFunction attribute attached to the method enables the execution of user-written code other than the basic registration of the COM class. Register calls the ShellExtReg.RegisterShellExtInfotipHandler method in ShellExtLib.cs to associate the handler with a certain file type. If the file type starts with '.', it tries to read the default value of the HKCR\<File Type> key which may contain the Program ID to which the file type is linked. If the default value is not empty, use the Program ID as the file type to proceed the registration.

For example, this code sample associates the handler with '.cs' files. HKCR\.cs has the default value 'VisualStudio.cs.10.0' by default when Visual Studio 2010 is installed, so we proceed to register the handler under HKCR\VisualStudio.cs.10.0\ instead of under HKCR\.cs. The following keys and values are added in the registration process of the sample handler.

    HKCR
    {
        NoRemove .cs = s 'VisualStudio.cs.10.0'
        NoRemove VisualStudio.cs.10.0
        {
            NoRemove shellex
            {
                {00021500-0000-0000-C000-000000000046} =
                    s '{B8D98AB4-376B-45D0-9CF6-8BF22A588989}'
            }
        }
    }

The unregistration is implemented in the Unregister method of FileInfotipExt. Similar to the Register method, the ComUnregisterFunction attribute attached to the method enables the execution of user-written code during the unregistration process. It removes the registry key: HKCR\<File Type>\shellex\{00021500-0000-0000-C000-000000000046}.

Download

http://1code.codeplex.com/releases

And find the CS/VB/CppShellExtContextMenuHandler samples in the Visual Studio 2010 folder.

If you have any feedback about the samples, please email onecode@microsoft.com.

Please stay tuned for Part 3 of the series, which will talk about writing Drag and Drop Handler in managed languages.

Posted on Monday, October 11, 2010 11:57 AM | Back to top


Comments on this post: Writing Windows Shell Extension with .NET 4 - Part 2

# re: Writing Windows Shell Extension with .NET 4 - Part 2
Requesting Gravatar...
Output of IQueryInfo instance will completely replace the original tooltip defined in the registry. Is it possible just to append content to the default tooltip?
Left by Tony on Mar 30, 2011 3:24 PM

# re: Writing Windows Shell Extension with .NET 4 - Part 2
Requesting Gravatar...
I concur with your conclusions and will eagerly look forward to your future updates. Regards. bottleless cooler
Left by leah on Nov 14, 2011 3:17 PM

# re: Writing Windows Shell Extension with .NET 4 - Part 2
Requesting Gravatar...
Great, Your article really fascinates the core of my interest. I admire how we removed the overall essence within your topic. Many thanks this site. pmp training
Left by alex on Nov 14, 2011 7:16 PM

# re: Writing Windows Shell Extension with .NET 4 - Part 2
Requesting Gravatar...
Thanks for this detail demo for writing windows shells really appreciate your work.
Left by Muffazal Lakdawala on Nov 28, 2011 7:02 PM

Your comment:
 (will show your gravatar)


Copyright © Geekswithblogs | Powered by: GeeksWithBlogs.net