File Manager ExtensionsFile Manager Extensions*
*Contents  *Index  *Topic Contents
*Previous Topic: Dragging and Dropping
*Next Topic: File Parsers

File Manager Extensions


In Microsoft® Windows®, File Manager extensions are dynamic-link libraries (DLLs) that add menus and buttons to File Manager. File Manager extensions can also display (in the status bar) Help text for the buttons. This document describes how to create and install extensions for File Manager.

About File Manager Extensions

File Manager maintains a list of extensions in an initialization file and loads the extensions when starting. An extension DLL contains an entry point that processes menu commands and notification messages sent by File Manager. Up to five extension DLLs can be installed at any one time.

Creating a File Manager Extension

A File Manager extension must reside in a DLL that includes a standard entry point, the Microsoft® Win32® FMExtensionProc callback function. The extension must include the Wfext.h header file that defines File Manager messages and structures. File Manager communicates with the extension DLL by sending the following messages to the DLL's FMExtensionProc function.
Message Meaning
1–99 The user selected an item from the extension-supplied menu. The value is the identifier of the selected menu item.
FMEVENT_HELPSTRING The user selected an extension menu or a toolbar command item. File Manager wants the extension to supply a Help string.
FMEVENT_HELPMENUITEM The user pressed F1 while selecting an extension menu or a toolbar command item. File Manager wants the extension to call WinHelp appropriately for the command item.
FMEVENT_INITMENU The user selected the extension's menu. The extension should initialize items in the menu.
FMEVENT_LOAD File Manager is loading the extension DLL and prompts the DLL for information about the menu that the DLL supplies.
FMEVENT_SELCHANGE Selection in the File Manager directory window or Search Results window has changed.
FMEVENT_TOOLBARLOAD File Manager is creating the toolbar and prompts the extension DLL for information about any buttons the DLL adds to the toolbar.
FMEVENT_UNLOAD File Manager is unloading the extension DLL.
FMEVENT_USER_REFRESH The user selected the Refresh command from the Window menu. The extension should update items in the menu, if necessary.

Creating the entry-point function

File Manager communicates with an extension DLL through the FMExtensionProc callback function. Make sure to export this function by listing it in the EXPORTS statement of your extension's module-definition (.def) file. The FMExtensionProc function handles the messages listed in the preceding section by performing the tasks listed below:
Task Action
Initializing the extension (FMEVENT_LOAD) Provides File Manager with the name and handle to the menu and saves the menu-item delta value.
Initializing the menu (FMEVENT_INITMENU) Initializes all top-level menu items and the items in any submenus.
Initializing the toolbar (FMEVENT_TOOLBARLOAD) Provides File Manager with information about the buttons to add to the toolbar, including the command identifier, Help string identifier, styles, and bitmap identifier.
Processing menu selections (1–99) Carries out commands that the user chooses from the extension's menu.
Processing file selections (FMEVENT_SELCHANGE) Queries File Manager for information about the file that the user has selected from the directory window or Search Results window.
Updating items in the menu (FMEVENT_USER_REFRESH) Modifies the menu as appropriate when the user chooses File Manager's Refresh command from the Window menu.
Providing menu item Help strings (FMEVENT_HELPSTRING) Provides File Manager with a Help string for a specified command in a specified menu. File Manager displays this string in the area at the bottom left of the window.
Passing menu item help requests on to WinHelp (FMEVENT_HELPMENUITEM) Provides WinHelp with the window passed by File Manager and with menu item information.
Quitting the extension DLL (FMEVENT_UNLOAD) Frees any memory allocated and prepares to exit.

The FMExtensionProc function is defined as follows:

LONG WINAPI FMExtensionProc(hwnd, wMsg, lParam) 
    HWND hwnd; 
    WORD wMsg; 
    LONG lParam; 
 

The hwnd parameter identifies the File Manager window. An extension should use this window handle to specify the parent window for any dialog box or message box it must display. It should also use this handle to send query messages to File Manager. The wMsg parameter contains one of the File Manager messages listed previously. The lParam parameter contains a message-specific value. The return value from the FMExtensionProc function depends on the value of the wMsg parameter.

The menu added to File Manager may be a hierarchical (cascaded) menu and may contain grayed, disabled, or checked menu items in addition to command items. Menu items should be text only; owner-drawn menus and bitmap menus are not supported. Changing the bitmap for check marks is not supported.

Whenever File Manager calls the FMExtensionProc function, it waits to refresh its directory windows (for changes in the file system) until after the function returns. This allows the extension to perform large numbers of file operations without excessive repainting on the part of File Manager. It is not necessary for the extension to send the FM_REFRESH_WINDOWS message to notify File Manager to repaint its directory windows.

Loading the extension

To begin loading the extension, File Manager first sends the FMEVENT_LOAD message to the FMExtensionProc function. The lParam parameter accompanying the FMEVENT_LOAD message points to an FMS_LOAD structure that File Manager uses to obtain information about the extension-supplied menu, including the menu name and menu handle.

File Manager also uses the FMS_LOAD structure to pass the menu-item delta value to the extension. To avoid conflicts with its own menu-item identifiers, File Manager renumbers the menu-item identifiers in an extension-supplied menu by adding the delta value to each identifier. An extension DLL that must modify its menu after File Manager has loaded it must use the delta value. For example, to delete a menu item, the extension DLL finds the sum of the delta value and the menu-item identifier and passes the sum as the idItem parameter to the DeleteMenu function.

If an extension returns FALSE in response to the FMEVENT_LOAD message, File Manager calls the FreeLibrary function and ends any communication with the extension DLL. This is the only place where an extension can notify File Manager of initialization problems and thus prevent the extension from being loaded.

Adding custom buttons

A File Manager extension can add custom buttons to the File Manager toolbar by returning button information in response to the FMEVENT_TOOLBARLOAD message. File Manager sends this message to the FMExtensionProc function of the extension only if the extension successfully installed a custom menu during the processing of the FMEVENT_LOAD message. Use custom buttons as accelerator keys for menu commands specified in the custom menu.

When FMExtensionProc receives the FMEVENT_TOOLBARLOAD message, the lParam parameter points to an FMS_TOOLBARLOAD structure. The File Manager extension must copy information about the custom buttons to the structure, including the number of buttons and a specifier for the bitmap containing the button images (either the identifier for a bitmap resource or a handle to a memory bitmap). The extension must also include the address of an array of EXT_BUTTON structures, each of which must contain a command identifier for the corresponding button. If the button is an accelerator for a menu command, the button identifier and corresponding menu-command identifier must be equal.

The bitmap containing the button images must be a bitmap resource or a memory bitmap. The extension must copy either the resource identifier or the memory bitmap's handle to the FMS_TOOLBARLOAD structure. In the case of a bitmap resource, the resource must be in the extension's executable file.

The bitmap must contain one image for each specified button. The bitmap height is always 15 pixels. The width is always a multiple of 16 pixels because each button image must be 16 pixels wide. Button images are concatenated from left to right. For example, the image of the first button specified in the array of EXT_BUTTON structures must be the leftmost image in the bitmap.

An extension can provide a line of Help text for a button by specifying the identifier of a string resource in the idsHelp member of the EXT_BUTTON structure. When the user selects the button, File Manager retrieves the string resource and displays it on the toolbar.

Processing menu selections

The menu resource that you define for your extension's menu must use menu-item identifiers in the range of 1 through 99. When the user selects an item, the extension receives a command notification that is the identifier of the selected item as defined in the resource definition file (which has the .rc file name extension). The command notification is not the sum of the delta value and the identifier. An extension DLL's FMExtensionProc function carries out commands by processing command notifications.

Initializing the extension menu

When the user selects the extension's main menu item from File Manager's menu bar, File Manager sends the FMEVENT_INITMENU message to the extension DLL. An extension can use this message to initialize its menu items. For example, an extension can add check marks, disable items, or gray items during this message. The extension must initialize all menu items, including those in any submenus, because File Manager will not send the FMEVENT_INITMENU message for submenus within the extension's menu.

Updating the extension menu

When the user chooses the Refresh command from the Window menu, File Manager sends an FMEVENT_USER_REFRESH message to an extension DLL. The extension can use this opportunity to update its menu items.

Processing file selections

When the user selects a file name in the directory window or in the Search Results window, File Manager sends the FMEVENT_SELCHANGE message to an extension DLL. The extension can use this opportunity to send a query message to File Manager to obtain more information about the user's selection.

Because the user can change the selection often, the extension should return promptly after processing the FMEVENT_SELCHANGE message to avoid slowing the user's selection process.

Quitting the extension dynamic-link library

When File Manager quits, it sends the FMEVENT_UNLOAD message to each extension DLL and then calls the FreeLibrary function to free the DLLs. Each DLL should free any memory that it has allocated.

Installing Extensions

File Manager installs extensions that have settings in the [AddOns] section of the Winfile.ini initialization file. Each setting contains an entry and a value. An entry consists of a string that represents the name of an extension. The value assigned to the entry consists of a string that specifies the path to the extension DLL. An application can use the WritePrivateProfileString function to add a setting to Winfile.ini. The following example shows a setting in Winfile.ini.

[AddOns] 
MyExtension=C:\NT\SYSTEM\MYEXT.DLL 
 

File Manager does not display an error message if it cannot find an extension DLL, so an extension DLL can be deleted in order to uninstall it. Even so, an application that installs an extension DLL should provide an uninstall option to remove the extension's setting from the Winfile.ini file.

Extension Messages

An extension can send the following window messages to retrieve relevant information from File Manager. File Manager is guaranteed to respond correctly only to messages sent from the extension's FMExtensionProc function.
Message Description
FM_GETDRIVEINFO File Manager returns drive information from the active window. An extension provides a pointer to an FMS_GETDRIVEINFO structure; File Manager fills the structure with drive information.
FM_GETFILESEL File Manager returns information about a selected file from the active File Manager window (either the directory window or the Search Results window). An extension provides a pointer to an FMS_GETFILESEL structure; File Manager fills the structure with file information.
FM_GETFILESELLFN Same as the FM_GETFILESEL message except that the selected file may have a long file name.
FM_GETFOCUS File Manager returns a value that identifies the type of window with input focus.
FM_GETSELCOUNT File Manager returns the count of selected files in the directory and Search Results windows.
FM_GETSELCOUNTLFN Same as the FM_GETSELCOUNT message except that the count includes files with long file names.
FM_REFRESH_WINDOWS File Manager repaints either its active window or all of its windows. This message is similar to File Manager's Refresh command on the Window menu.
FM_RELOAD_EXTENSIONS File Manager reloads all extensions. First, File Manager unloads all extensions, sending an FMEVENT_UNLOAD message to each extension. Then it reloads the extensions, sending an FMEVENT_LOAD message to each extension. The FM_RELOAD_EXTENSIONS message allows an extension to uninstall itself by removing its setting from the Winfile.ini file; this action causes File Manager to reload the remaining extensions. Other applications and programs (for example, installation programs) can also post this message by calling the PostMessage function.

Processing Commands and Messages from File Manager

The following code shows the FMExtensionProc function for a sample extension DLL. It demonstrates how an extension processes the menu commands and notification messages sent by File Manager.

HINSTANCE hinst; 
HMENU hmenu; 
WORD wMenuDelta; 
BOOL fMultiple = FALSE; 
BOOL fLFN = FALSE; 
 
LONG WINAPI FMExtensionProc(hwnd, wMsg, lParam) 
HWND hwnd; 
WORD wMsg; 
LONG lParam; 
 
{ 
    CHAR szBuf[200]; 
    INT count; 
 
    switch (wMsg) { 
    case FMEVENT_LOAD: 
 
       #define lpload  ((LPFMS_LOAD) lParam) 
 
       /* Save the menu-item delta value. */ 
 
       wMenuDelta = lpload->wMenuDelta; 
 
       /* Fill the FMS_LOAD structure. */ 
 
       lpload->dwSize = sizeof(FMS_LOAD); 
       lstrcpy(lpload->szMenuName, "&Extension"); 
 
       /* Return the handle to the menu. */ 
 
       hinst = GetModuleHandle("ext.dll"); 
       lpload->hMenu = GetSubMenu(LoadMenu(hinst, 
       MAKEINTRESOURCE(MYMENU)), 0); 
 
       return (LONG)TRUE; 
 
   case FMEVENT_UNLOAD: 
 
       /* Perform any cleanup procedures here. */ 
 
       break; 
 
   case FMEVENT_INITMENU: 
 
       /* Copy the menu handle. */ 
 
       hmenu = (HMENU) lParam; 
 
       /* 
             * Add check marks to menu items as appropriate. 
             * Add menu-item delta values to menu-item 
             * identifiers to specify the menu items to check. 
        */ 
 
       CheckMenuItem(hmenu, 
               wMenuDelta + IDM_MULTIPLE, 
               fMultiple ? MF_BYCOMMAND | MF_CHECKED : 
                       MF_BYCOMMAND | MF_UNCHECKED); 
       CheckMenuItem(hmenu, 
               wMenuDelta + IDM_LFN, 
               fLFN ? MF_BYCOMMAND | MF_CHECKED : 
                       MF_BYCOMMAND | MF_UNCHECKED); 
       break; 
 
   case FMEVENT_TOOLBARLOAD: 
   { 
       static EXT_BUTTON extbtn[] = { 
          {1, 0, 0}, 
       }; 
 
            /* Fill the FMS_TOOLBARLOAD structure. */ 
 
       #define lptbld ((LPFMS_TOOLBARLOAD) lParam) 
 
       lptbld->dwSize = sizeof(FMS_TOOLBARLOAD); 
       lptbld->lpButtons = (LPEXT_BUTTON) &extbtn; 
       lptbld->cButtons = 1; 
       lptbld->cBitmaps = 1; 
       lptbld->idBitmap = ID_BUTTONBITMAP; 
 
       return (LONG)TRUE; 
 
   } 
 
   case FMEVENT_USER_REFRESH: 
            MessageBox(hwnd, "User refresh event", 
                "Hey!", MB_OK); 
       break; 
 
   case FMEVENT_SELCHANGE: 
       break; 
 
        /* 
         * The following messages are generated when the user 
         * chooses items from the extension menu. 
         */ 
 
   case FMEVENT_HELPSTRING: 
 
       #define lphs ((LPFMS_HELPSTRING)lParam) 
 
       if (lphs->idCommand == -1) 
          lstrcpy(lphs->szHelp, "Help for extension menu"); 
       else 
          wsprintf(lphs->szHelp, "Help for item %d", lphs->idCommand); 
 
       break; 
 
   case FMEVENT_HELPMENUITEM: 
 
       wsprintf(szBuf, "Help for %d", lParam); 
       MessageBox(hwnd, szBuf, "WinHelp call", MB_OK); 
 
       /* 
        * Use: WinHelp(hwnd, "ExtHelp.hlp", HELP_CONTEXT, lParam); 
        */ 
 
       break; 
 
   case IDM_GETFOCUS: 
       wsprintf(szBuf, "Focus %d", 
               (INT) SendMessage(hwnd, FM_GETFOCUS, 0, 0)); 
       MessageBox(hwnd, szBuf, "Focus", MB_OK); 
       break; 
 
   case IDM_GETCOUNT: 
       count = (INT) SendMessage(hwnd, 
                fLFN ? FM_GETSELCOUNTLFN : FM_GETSELCOUNT, 
                0, 0); 
 
       wsprintf(szBuf, "%d files selected", count); 
       MessageBox(hwnd, szBuf, "Selection Count", MB_OK); 
       break; 
 
   case IDM_GETFILE: 
   { 
       FMS_GETFILESEL file; 
 
       count = (INT) SendMessage(hwnd, 
               fLFN ? FM_GETSELCOUNTLFN : FM_GETSELCOUNT, 
               FMFOCUS_DIR, 
               0); 
 
       while (count >= 1) { 
                /* 
                 * Selection indices are zero-based (0 is 
                 * first). 
                 */ 
 
      count--; 
      SendMessage(hwnd, FM_GETFILESEL, count, 
          (LONG) (LPFMS_GETFILESEL) &file); 
      wsprintf(szBuf, "file %s\nSize %ld", 
          (LPSTR) file.szName, file.dwSize); 
                MessageBox(hwnd, szBuf, "File Information", 
                    MB_OK); 
 
      if (!fMultiple) 
         break; 
       } 
       break; 
   } 
 
   case IDM_GETDRIVE: 
   { 
       FMS_GETDRIVEINFO drive; 
 
       SendMessage(hwnd, FM_GETDRIVEINFO, 0, 
       (LONG) (LPFMS_GETDRIVEINFO)&drive); 
       wsprintf(szBuf, 
                "%s\nFree %ld\nTotal %ld\nVolume %s\nShare %s", 
       (LPSTR) drive.szPath, drive.dwFreeSpace, 
       drive.dwTotalSpace, (LPSTR) drive.szVolume, 
       (LPSTR) drive.szShare); 
       MessageBox(hwnd, szBuf, "Drive Info", MB_OK); 
       break; 
   } 
 
   case IDM_LFN: 
       MessageBox(hwnd, "IDM_LFN", "Hi", MB_OK); 
       fLFN = !fLFN; 
       break; 
 
   case IDM_MULTIPLE: 
       MessageBox(hwnd, "IDM_MULTIPLE", "Hi", MB_OK); 
       fMultiple = !fMultiple; 
       break; 
 
   case IDM_REFRESH: 
   case IDM_REFRESHALL: 
       SendMessage(hwnd, FM_REFRESH_WINDOWS, 
       wMsg == IDM_REFRESHALL, 0); 
       break; 
 
   case IDM_RELOAD: 
       PostMessage(hwnd, FM_RELOAD_EXTENSIONS, 0, 0); 
       break; 
    } 
    return 0L; 
} 
 

Adding the Undelete Command

File Manager supports a hook for adding an Undelete command to the File menu. If an undelete dynamic-link library is specified in the Winfile.ini file, File Manager adds the Undelete command to the File menu when starting. When the user chooses the Undelete command, File Manager calls the DLL.

The [settings] section of the Winfile.ini file should include a reference to the undelete DLL, as follows:

[settings] 
UNDELETE.DLL=C:\MYDIR\OTHER.DLL 
 

An undelete DLL must include a standard entry point, the UndeleteFile function. This function must be exported by specifying the name of the function in the EXPORTS statement of the DLL's module-definition (.def) file.

The UndeleteFile function is defined as follows:

DWORD APIENTRY UndeleteFile(hwndParent, lpszDir) 
    HWND hwndParent; 
    LPSTR lpszDir; 
 

The hwndParent parameter identifies the parent window for any dialog boxes the DLL creates. The lpszDir parameter specifies the initial directory to be used (for example, C:\TEMP).


Up Top of Page
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.