Random Post: Culture Shock
RSS .92| RSS 2.0| ATOM 0.3
  • Home
  • About
  • Eric’s Toolset
  • Free Software
  • Software License
  •  

    .NET Context Menu Handler

    April 7th, 2005 by Eric

    I’ve been working on a context menu handler shell extension in C# lately. There are a few samples that people have produced on the web (for example, The Code Project, pek.com, and TheServerSide.net). I’ve found a better way of implementing IShellExtInit.Initialize than in the examples I’ve seen.

    The point of IShellExtInit.Initialize is for the shell to let your handler know which files are selected so that you can display your context menu based on, believe it or not, context. Here is a typical implementation:

    int IShellExtInit.Initialize (IntPtr pidlFolder, IntPtr lpdobj, uint hKeyProgID) 
    { 
      try 
      { 
        // save the information about the selection 
        m_dataObject = null; 
        if (lpdobj != (IntPtr)0) 
        { 
          m_dataObject = (ShellLib.IDataObject)Marshal.GetObjectForIUnknown(lpdobj); 
          FORMATETC fmt = new FORMATETC(); 
          fmt.cfFormat = CLIPFORMAT.CF_HDROP; 
          fmt.ptd = 0; 
          fmt.dwAspect = DVASPECT.DVASPECT_CONTENT; 
          fmt.lindex = -1; 
          fmt.tymed = TYMED.TYMED_HGLOBAL; 
          STGMEDIUM medium = new STGMEDIUM(); 
          m_dataObject.GetData(ref fmt, ref medium); 
          m_hDrop = medium.hGlobal; 
        } 
      } 
      catch(Exception) 
      { 
      } 
      return 0; 
    }

    Then later on, to get the selected file:

    // Get the file name to work with 
    StringBuilder sb = new StringBuilder(1024); 
    Helpers.DragQueryFile(m_hDrop, 0, sb, sb.Capacity + 1);

    There’s a fair amount of nasty interop going on here, which is sometimes inevitable for things like shell extensions. In this case, however, you can actually use the .NET Framework’s DataObject class instead for much simpler code:

    int IShellExtInit.Initialize (IntPtr pidlFolder, IntPtr lpdobj, uint hKeyProgID) 
    { 
      DataObject dataObject = new DataObject(lpdobj); 
      string[] selectedFiles = (string[])dataObject.GetData(DataFormats.FileDrop); 
    }

    One Response to “.NET Context Menu Handler”

    1. Eric says:

      Though I’ve since learned that writing shell extensions in managed code is a Bad Thing. Raymond Chen mentions this in reference to a discussion thread on MSDN.

      The trouble is that only one version of the CLR can be loaded into a process at a time. If you use .NET 2.0, but another extension uses 1.1, and that other extension gets loaded first, then you lose.

    Leave a Reply