HOWTO: Support Renaming of Items in the Windows Explorer Tree

ID: Q179900


The information in this article applies to:
  • Microsoft Win32 Software Development Kit (SDK)
  • Microsoft Windows 2000


SUMMARY

When creating a namespace extension that has multiple levels of folders, it may be necessary to allow the folders to be renamed. This article discusses how to support renaming of folders in the Windows Explorer tree. This article assumes you are already familiar with development of namespace extensions. For more information on writing namespace extensions, see David Campbell's article "Extending the Windows Explorer with Name Space Extensions" in the July, 1996 issue of the Microsoft Systems Journal. In addition, please see the following article in the Microsoft Knowledge Base:

Q178665 SAMPLE: RegView.exe: Shell Namespace Extension Example


MORE INFORMATION

To support renaming of folders in the Windows Explorer tree, follow these steps:

  1. Supply the SFGAO_CANRENAME attribute in response to your IShellFolder::GetAttributesOf method for any folders that can be renamed.

    Explorer will call your IShellFolder::GetAttributesOf with the PIDL of a folder in your namespace. If this item can be renamed, you need to add the SFGAO_CANRENAME attribute to the attributes for that item. Don't forget that you can call IShellFolder::GetAttributesOf with multiple PIDLs, so you must only return the attributes that apply to all items. When Windows Explorer detects the SFGAO_CANRENAME attribute for the selected folder in the tree, it will enable the Rename item in the File menu.

    An example of GetAttributesOf might look something like this:

    Sample Code
    
          STDMETHODIMP CShellFolder::GetAttributesOf(  UINT uCount,
                                                       LPCITEMIDLIST aPidls[],
                                                       LPDWORD pdwAttribs)
          {
          UINT  i;
    
          for(i = 0; i < uCount; i++)
             {
             DWORD dwAttribs = 0;
    
             // Is this item a folder?
             if(IsFolder(aPidls[i]))
                {
                dwAttribs |= SFGAO_FOLDER;
    
                // Does this folder item have any subfolders?
                if(HasSubFolders(aPidls[i]))
                   dwAttribs |= SFGAO_HASSUBFOLDER;
    
                // Can this folder be renamed?
                if(CanRename(aPidls[i]))
                   dwAttribs |= SFGAO_CANRENAME;
                }
    
             /*
             On entry, *pdwAttributes contains the attributes that are being
             requested, so just use it as a mask.
             */ 
             *pdwAttribs &= dwAttribs;
             }
    
          return S_OK;
          } 


  2. Add a rename item to the context menu in your IContextMenu::QueryContextMenu.

    To support renaming of tree items you must also add a rename item to the context menu supplied for a folder item in the tree. Windows Explorer calls your IShellFolder::GetUIObjectOf with IID_IContextMenu to get the IContextMenu for the folder item. When this IContextMenu's QueryContextMenu method is called, you need to add a rename item to the menu if CMF_CANRENAME is specified and then enable or disable the rename menu item based on the item's SFGAO_CANRENAME attribute. A context menu can be created for multiple items. As a result, you should disable the rename menu item if the context menu is created for more than one item because renaming of multiple items is generally not implemented. The rename menu item can have any command identifier as long as it is unique with respect to the other items in the menu. Remember that the string set for the rename menu item should be localized so that various languages can be supported.

    Following is an example of what an IContextMenu::QueryContextMenu could look like. This sample code assumes that the context menu object maintains a NULL-terminated list of the items that it was created for in its m_aPidls member variable and a pointer to the IShellFolder that created it in its m_pSFParent member variable.

    Sample Code
    
          #define IDM_MYRENAME 0
          #define IDM_LAST     5
    
          STDMETHODIMP CContextMenu::QueryContextMenu( HMENU hMenu,
                                                       UINT indexMenu,
                                                       UINT idCmdFirst,
                                                       UINT idCmdLast,
                                                       UINT uFlags)
          {
          if(!(CMF_DEFAULTONLY & uFlags))
             {
             MENUITEMINFO   mii;
    
             // Add any other menu items here.
    
             if(uFlags & CMF_CANRENAME)
                {
                ZeroMemory(&mii, sizeof(mii));
                mii.cbSize = sizeof(mii);
                mii.fMask = MIIM_ID | MIIM_TYPE;
                mii.wID = 0;
                mii.fType = MFT_SEPARATOR;
                InsertMenuItem(   hMenu,
                                  indexMenu++,
                                  TRUE,
                                  &mii);
    
                ZeroMemory(&mii, sizeof(mii));
                mii.cbSize = sizeof(mii);
                mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
                mii.wID = idCmdFirst + IDM_MYRENAME;
                mii.fType = MFT_STRING;
                mii.dwTypeData = TEXT("&Rename");
                mii.fState = (CanRenameItems() ? MFS_ENABLED : MFS_DISABLED);
                InsertMenuItem(   hMenu,
                                  indexMenu++,
                                  TRUE,
                                  &mii);
                }
    
             // Add the following menu items here.
    
             return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_LAST + 1));
             }
    
          return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
          }
    
          BOOL CContextMenu::CanRenameItems(void)
          {
          if(m_aPidls)
             {
             // Get the number of items assigned to this object.
             UINT  i;
             for(i = 0; m_aPidls[i]; i++)
                {
                }
    
             // You can't rename more than one item at a time.
             if(i > 1)
                return FALSE;
    
             DWORD dwAttributes = SFGAO_CANRENAME;
             m_pSFParent->GetAttributesOf(i, (LPCITEMIDLIST*)m_aPidls,
          &dwAttributes);
    
             return dwAttributes & SFGAO_CANRENAME;
             }
    
          return FALSE;
          } 


  3. Supply the "rename" verb in response to your IContextMenu::GetCommandString method when GCS_VERB is specified.

    When an item in the menu is selected, Windows Explorer calls your IContextMenu::GetCommandString with GCS_VERB with the command ID of the selected menu item to determine if this menu item supports the "rename" verb. It does this specifically to allow a namespace extension to support renaming of items in the tree. If your GetCommandString supplies the "rename" verb for the selected menu item, it places the tree item into edit mode and return.

    If your extension is built with UNICODE defined, GCS_VERB will be defined as GCS_VERBA or GCS_VERBW. There is a problem with this on some platforms. Windows NT 4.0 without Internet Explorer or with Internet Explorer 3.0x will always pass GCS_VERBW, even if the extension was built with UNICODE defined or not. This was corrected with Internet Explorer 4.0x where it calls GetCommandString with GCS_VERBW and, if that fails, it then calls GetCommandString with GCS_VERBA. Windows 95 always passes GCS_VERBA because Windows 95 doesn't support UNICODE extensions. To make sure that all platforms are supported, you should handle the GCS_VERBA and GCS_VERBW cases explicitly.

    Also remember that the "rename" verb is not localized, so it will always be the string "rename". The case of the verb is ignored when the comparison is made.

    Sample Code

    An example of GetCommandString might look something like this:
    
          STDMETHODIMP CContextMenu::GetCommandString( UINT idCommand,
                                                       UINT uFlags,
                                                       LPUINT lpReserved,
                                                       LPTSTR lpszName,
                                                       UINT uMaxNameLen)
          {
          HRESULT  hr = E_INVALIDARG;
    
          switch(uFlags)
             {
             case GCS_VERBA:
                switch(idCommand)
                   {
                   case IDM_MYRENAME:
                      lstrcpynA((LPSTR)lpszName, "rename", uMaxNameLen);
                      hr = NOERROR;
                      break;
                   }
                break;
    
             /*
             Windows NT 4.0 with Internet Explorer 3.0x or no Internet Explorer
             will always call this with GCS_VERBW. In this case, you need to do
             the lstrcpyW to the pointer passed.
             */ 
             case GCS_VERBW:
                switch(idCommand)
                   {
                   case IDM_MYRENAME:
                      lstrcpynW((LPWSTR)lpszName, L"rename", uMaxNameLen);
                      hr = NOERROR;
                      break;
                   }
                break;
             }
    
          return hr;
          } 


This only allows items in the Windows Explorer tree to enter the rename mode. Once it enters rename mode and the user changes the name of the item, Windows Explorer will call your IShellFolder::SetNameOf method with the new name to change the name of the item.


REFERENCES

Microsoft Systems Journal, July 1996, "Extending the Windows Explorer with Name Space Extensions," page 41, David Campbell

For additional information, please see the following article in the Microsoft Knowledge Base:

Q178665 SAMPLE: RegView.exe: Shell Namespace Extension Example

Additional query words:

Keywords : kbExtension kbNameSpace kbNTOS400 kbWinOS2000 kbSDKWin32 kbWinOS95 kbWinOS98 kbGrpShell
Version : WINDOWS:
Platform : WINDOWS
Issue type : kbhowto


Last Reviewed: January 25, 2000
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.