Windows 3.11 File Manager Drag and Drop Process

In Microsoft Windows 3.11, dragging files from File Manager onto an active application window relied on a lightweight drag-and-drop mechanism managed by SHELL.DLL. This article explains the underlying architecture of that process, detailing how destination applications registered to accept files, how File Manager initiated and tracked the transfer, and how Windows dispatched the WM_DROPFILES message to hand off file path data between 16-bit processes.

1. Target Window Registration

Before an active application could receive files from File Manager (WINFILE.EXE), it had to notify the operating system of its capability.

The application called the DragAcceptFiles function from SHELL.DLL:

DragAcceptFiles(hWndTarget, TRUE);

This API call altered the internal window attributes of the target handle (hWndTarget), setting an internal flag equivalent to the WS_EX_ACCEPTFILES style. This flag told the Windows window manager and File Manager that the window could act as a valid drop target.

2. Initiating the Drag from File Manager

When a user selected one or more files in File Manager and held down the left mouse button, File Manager entered a modal mouse-tracking loop using SetCapture.

As the mouse moved across the desktop:

  • File Manager determined the window handle directly beneath the cursor using standard Win16 hit-testing routines (such as WindowFromPoint).
  • It queried whether the window beneath the cursor was registered to accept drops.
  • File Manager updated the mouse cursor to provide visual feedback: displaying a document-shaped drag cursor over valid drop targets, or a circle-with-a-slash ("no drop") cursor over invalid targets.

3. Creating the HDROP Structure and Dispatch

When the user released the mouse button over a registered target window:

  1. Memory Allocation: File Manager allocated a block of globally shared memory using GlobalAlloc with the GMEM_SHARE (or GMEM_DDESHARE) flag.
  2. Data Structure Population: File Manager populated this memory block with an internal structure known as DROPSTRUCT (or a list of null-terminated strings followed by a double null character). This structure stored:
    • The coordinates (X, Y) where the drop occurred, relative to the target's client area.
    • A flag indicating whether the drop occurred in the client or non-client area.
    • An array containing the fully qualified paths of all selected files.
  3. Handle Creation: The handle to this global memory block was cast as an HDROP handle.
  4. Message Posting: File Manager posted the WM_DROPFILES message directly to the target window’s queue:
PostMessage(hWndTarget, WM_DROPFILES, (WPARAM)hDrop, 0L);

4. Application Processing and File Retrieval

Upon receiving WM_DROPFILES, the target application processed the HDROP handle passed in wParam using helper routines provided by SHELL.DLL:

  • Querying File Count: The application determined the total number of files dropped by passing an index of 0xFFFFFFFF (-1) to DragQueryFile:
    UINT fileCount = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
  • Retrieving File Names: The application looped through the indices (0 to fileCount - 1), calling DragQueryFile to copy each file path into a local buffer:
    char szFilePath[MAX_PATH];
    DragQueryFile(hDrop, i, szFilePath, sizeof(szFilePath));
  • Drop Coordinates (Optional): If the application cared about the drop location, it called DragQueryPoint(hDrop, &point).

5. Memory Cleanup

Because the memory block backing HDROP was allocated globally, the receiving application was responsible for releasing it once processing finished. The application called:

DragFinish(hDrop);

DragFinish called GlobalFree on the memory handle, releasing the resources back to the Windows 16-bit global heap and concluding the drag-and-drop transaction.