Saturday, June 10, 2006

CopyFilenames Shell Extension

Overview

CopyFilenames is a free Shell Extension for Windows Explorer which allows you to copy the full filenames of one or more files to the clipboard. You can then paste the filename(s) into another document or email, or even directly into the filename box in your web-browser. No more searching for that file!

Download

CopyFilenames should work on all versions of Windows. No other files are needed. Download the Windows Installer package here [SetupCopyFilenames.msi - 283Kb] - follow the instructions in the setup installer.

Background

When browsing files with the Windows Explorer interface, I find I often want to copy/paste the name of a file or group of files.

For example, when uploading an image or document in my webbrowser, without CopyFilenames, I would click Browse... and then be forced to traverse the directory tree to find the file, which I can see in the Explorer window on screen!

Or perhaps I want to make reference to a group of files in a document. I want to be able to grab their filenames quickly, without resorting to a nasty command prompt dir *.jpg > filenames.txt command.

Source Code

The code was written in Delphi 5, because it has great support for simple COM/ActiveX objects, and doesn't require the .Net Framework, so CopyFilenames can run on almost every version of Windows.

The gubbins of the source is as follows:

  // ...

  // Render the data referenced by the IDataObject pointer to an HGLOBAL
  // storage medium in CF_HDROP format.
  Result := lpdobj.GetData(FormatEtc, StgMedium);
  if Failed(Result) then
    Exit;

  try

    // We collect a list of filenames for all items selected 
    // and store them in a string list object for later use.
    //
    //
    numFiles := DragQueryFile(StgMedium.hGlobal, $FFFFFFFF, nil, 0);
    _InitFilesList(numFiles); // preps the list with the correct number of slots

    for i:= 0 to numFiles-1 do
    begin
      filenameLength := DragQueryFile(StgMedium.hGlobal, i, nil, 0);
      DragQueryFile(StgMedium.hGlobal, i, LFileNameBuffer, SizeOf(LFileNameBuffer));
      filename := LFileNameBuffer;

      FFilenames[i] := filename;
    end;

    Result := NOERROR;

  finally
    ReleaseStgMedium(StgMedium);
  end;

  // ...

The details are pretty arcane, but most of the heavy-lifting is done by the Windows Explorer interface and the Shell handlers, which provide us with all the information we need. We convert it to Delphi-style strings, then copy the info up the clipboard, with each filename separated by a newline.

Any comments welcome.