Virtual Developer Workshop: Containerized Development with Docker

A single file selection...
Shell Extension to copy path of filename

Multiple files selected...
Shell Extension to copy path of 

Environment: VC6 SP3, NT4 SP5, IE5

There numerous times that I've wished I could simply right-click on a file, and copy its full pathname in order to paste it into an e-mail or a file open dialog. I finally decided to write it myself and thought someone else might find it useful. The extension adds a 'Copy Path' command to the context menu for a single file/folder selection and a 'Copy All Paths' command for multi-file/folder selection. For a single selection the complete pathname of the file is simply placed on the clipboard. For a multi-file selection, all the paths of the files are placed on the clipboard separated by <cr><lf> pairs.

One unexpected 'feature' is that you can right-click on a shortcut and the path of the target will be copied to the clipboard. Of course, the shortcut can be anywhere, including shell menu items if the IE4 active desktop option is installed.

Some of the code was based on code written by Dino Esposito from his book, Visual C++ Window Shell Programming (Wrox). This is an excellent resource for shell programming. I've run across a few things that his book didn't cover and found a bug related to a newer version of IE (I think).

This has been tested only on NT4 SP5 with IE5, and 95 without IE.


This is not a tutorial on shell extensions. I'll just give a brief overview of the requirements for a shell extension with some specifics about this example. There are several good resources, one of the best of which is the book I mentioned earlier by Dino Esposito, Visual C++ Window Shell Programming. Chris Losinger also has an example, Shell Extension Context Menu Sample at CodeGuru.

I started building this component by simply creating an ATL COM project, and then adding a simple ATL object. I then added the necessary interfaces and their implementations. A shell extension requires implementation of two interfaces, IShellExtInit and IContextMenu.

IShellExtInit has only one method, Initialize which is used to get the name of the files that have been selected (this extension only gets the name of the file with the current focus, although it could be expanded to be disabled if multiple files were selected, or to put all the paths on the clipboard.)

IContextMenu has three methods to implement, GetCommandString, InvokeCommand, and QueryContextMenu.

  • QueryContextMenu is called when the extension is first loaded to get the text and ID for the context menu item.
  • InvokeCommand is called when the user invokes the menu item.
  • GetCommandString can be called in different situations, but for this example we only care when it is called to get the help text associated with the command.

    I had a bit of trouble getting this to work correctly and I think it has to do with most recent IE installation. Following is the code for GetCommandString:

    // IContextMenu::GetCommandString
    HRESULT CCopyPathExt::GetCommandString(UINT /*idCmd*/, UINT uFlags, 
     UINT* /*pwReserved*/, LPSTR pszText, UINT cchMax)
     try {
       // We don't care about the command ID, since we have a 
       // single item
       // This is rather funky, but GCS_HELPTEXTA refers to a 
       // single bit (4) and GCS_UNICODE refers to single bit 
       // (1), but GCS_HELPTEXTW is a combination
       // of those values (5).  This works on both NT and 95.
       if ( uFlags & GCS_HELPTEXTA ) {
        // I'm assuming that this value always contains the number 
        // of bytes available for the message, just to be safe.  
        // So half it for Unicode characters.
        const int cChars = cchMax / sizeof(TCHAR);
        // Create some storage on the stack for building the 
        // help text
        LPTSTR szHelpText = 
         reinterpret_cast( _alloca( cChars ) );
        memset( szHelpText, 0, cChars );
        // Create a generic version of the help text depending on 
        // the number of file selected
        if ( 1 == m_cFiles ) {
         _sntprintf( szHelpText, cChars - 1, 
          _T("Copy full path of file to clipboard (%s)"), m_szFile);
        } else {
         const LPTSTR szMultiFileHelpText = 
          _T("Copy full paths of selected files to clipboard");
         _tcsncpy( szHelpText, szMultiFileHelpText, min(cChars - 1, 
          _tcslen( szMultiFileHelpText ) ) );
        // Do character conversion depending on flag
        if ( uFlags & GCS_UNICODE ) {
         wcsncpy( reinterpret_cast(pszText), 
          T2W(szHelpText), cChars );
        } else {
         strncpy(pszText, T2A(szHelpText), cchMax);
      } catch ( ... ) {
      return E_FAIL;
     return S_OK;
  • Most examples simply test for the bits GCS_HELPTEXTA or GCS_HELPTEXTW, but the value of GCS_HELPTEXTW is actually 5, not a single bit value, which is also equal to GSC_HELPTEXTA|GCS_UNICODE. So, I simply test for GCS_HELPTEXTA and then test for the GCS_UNICODE bit. I also assume that if GetCommandString requests a Unicode string, then the max length of the string is half of what it would normally be. This may be incorrect, but it's a safe guess.

Future work

  • There are 'extended' commands for the shell that are displayed when the user holds down the SHIFT key. For example, under NT, you'll get the additional commands 'Compress', 'Uncompress', and 'Open With...' (even if the file already has an association). I would like to add extended commands that only copy the filename(s) not the path (fewer keystrokes than F2, Ctrl-C, ESC). The documentation for IContextMenu::QueryContextMenu states that the CMF_EXTENDEDVERBS "...is set when the calling application wants extended verbs. Normal verbs are displayed when the user right-clicks an object. To display extended verbs, the user must right-click while pressing the SHIFT key." But, I could not get this to work nor find any examples. Let me know if you know how to do this.
  • The bitmap for the icon gets XORed by the shell to make it look darker than it should. I've read that IContextMenu3 needs to be implemented to handle an ownerdraw menuitem in order to make the icons like as nice as the 'Send To' icons. A fix for this would be nice.
  • Finally, I would like to put together an ATL Object wizard to help jumpstart the creation of these shell extensions. I'll do it if someone requests it.


Download source and DLL - 87 Kb


  • It is not working on vista

    Posted by drop2kumar on 06/04/2007 08:40am

    I have tried the same with vista....but IShellExInit is bot working

  • What's the install procedure?

    Posted by Harmonitron on 08/30/2005 10:30pm

    Do I just dump the DLL in the Windows folder or System32? Thanks from Ireland.

  • Sorry, error!!!

    Posted by maxxx on 06/08/2005 03:33am

    I have VC++ 7, and my linker send message: error C2787: 'IContextMenu' : no GUID has been associated with this object Please help.

    • Re: 'IContextMenu' : no GUID has been associated

      Posted by brianbondy101 on 06/13/2007 05:54pm

      Hi maxxx;
      The response is for people that find this thread by searching for the same error.
      Just define at the top of the stdafx.h file above your includes:
      #define _ATL_NO_UUIDOF

      Brian R. Bondy

  • Managed C++

    Posted by Filbert Fox on 05/12/2005 12:11pm

    I have you thought about converting this too managed C++, I am trying to write a windows shell for C++ .NET and having problems...

  • This is great!

    Posted by Legacy on 12/10/2000 08:00am

    Originally posted by: Lee Johnson

    I've haunting such simple and useful utility for several month and you solved the problem for me!

    But could I add a short-cut key to this command? Or could you please just advise on how to do this?

  • copy files (all including dependent file)

    Posted by Legacy on 01/22/2000 08:00am

    Originally posted by: Md.Hidayathulla

    Hello sir,

    I would like copy all files in an vc++ project.i.e all
    source files,header files ,resource files & external
    dependent files.
    #include <stdafx.h>
    #include "..\test.h"

    so when i copy program1.cpp to any target,i would like to
    copy all included files to target.
    so please help me out in doing this.
    wating for ur reply.

    with regards.

  • Nice but MS PowerToys has a SendTo extension that does it.

    Posted by Legacy on 01/20/2000 08:00am

    Originally posted by: Shmulik Flint

    Anyway, this is easier and nicer (and we have the code :-})

  • Cool Util, but how do i register the shell ext?

    Posted by Legacy on 01/16/2000 08:00am

    Originally posted by: Shay Erlichmen

    Can you attach the a reg file for registering the shell ext.

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date