Creating Menus and Menu Commands

The Acrobat core API supports creating new menu commands and modify existing menus. A menu command lets a user interact with your plugin by clicking a menu command that is displayed in an Adobe Reader or Acrobat menu. When the user clicks the menu command, application logic that is defined in the callback function associated with the menu command is executed. It is your responsibility to define the application logic that is located in the callback function.

About menus

Adobe Reader and Acrobat have a standard menu bar and menu that let a user invoke specific functionality. You can, for example, click the Open command that is located on the File menu to open an existing PDF file. Using the Acrobat core API, you can programmatic-ally modify the menu bar. The following illustration shows the menu bar located in Acrobat.

_images/menu.png

Letter

Description

A

The Acrobat menu bar.

B

An Acrobat menu.

C

A menu command.

About AVmenubar typedefs

An AVmenubar typedef represents the menu bar located within Adobe Reader or Acrobat and contains a list of all menus. A plugin can only have one AVmenubar object. You can add new menus to the menu bar, remove menus from the menu bar, or hide the menu bar by using the Acrobat core API.

About AVMenu typedefs

An AVMenu typedef represents a menu in the Adobe Reader or Acrobat menu bar. You can create new menus, add menu commands to a menu, and remove menu items. Deleting an AVMenu removes it from the menu bar (if it was attached) and deletes all the menu items it contains.

Submenus (also called pull right menus) are AVMenu objects that are attached to an AVMenuItem object instead of to the menu bar.

Each menu has a title and a language-independent name. The title is the string that appears in the user interface, while the language-independent name is the same regardless of the language used in the user interface. Language-independent names enable a plugin to locate a specific menu, such as the File menu, without knowing, for example, that it is called Fichier in French.

You are strongly encouraged to begin your language-independent menu names with the plugin name (separated by a colon) to avoid name collisions when more than one plugin is present. For example, if a plugin is named myPlug, it may add a menu whose name is myPlug:Options. (See Using plugin prefixes.)

About AVMenuItem typedefs

An AVMenuItem is a menu command within a menu. It contains the following attributes:

  • A name

  • A keyboard shortcut

  • A callback function to execute when the menu item is selected

  • A callback function to compute whether the menu item is enabled

  • A callback function to compute whether the menu item is check marked, and whether it has a submenu

An AVMenuItem object can also serve as a separators between menu commands. You are encouraged to position your plugin menu commands relative to a separator. This helps ensure that if a block of menu commands is moved in a future version of Acrobat, your plugin menu commands also are moved.

A plugin can simulate a user selecting a menu command by invoking the AVMenuItemExecute method. If the menu command is disabled, the AVMenuItemExecute method returns without performing a task. The AVMenuItemExecute method works even when the menu item is not displayed (for example, if it has not been attached to a menu or if the menu bar is not visible). You can set the attributes of all menu commands that you create; however, do not modify the Execute procedure of the Acrobat built-in menu commands.

Your plugin can specify menu command names using either the names seen by a user, or language-independent names. The latter allows your plugin to locate a specific menu command without knowing, for example, that it is called Imprimer in French.

You are strongly encouraged to avoid name collisions when naming menu commands by using your plugin name and a colon. For example, if a plugin is named myPlug, you can name a menu command myPlug:Open or myPlug:Find. (See Using plugin prefixes.)

Adding menu commands to menus

You can use the Acrobat core API to add a new menu command to an existing menu. For example, you can add a menu named Acrobat SDK to the Adobe Reader or Acrobat menu bar.

To add a new menu command to an existing menu, perform the following tasks:

  1. Retrieve the Adobe Reader or Acrobat menu bar that is represented by an AVmenubar object by invoking the AVAppGetMenubar method.

AVMenubar Themenubar = AVAppGetMenubar();
  1. Retrieve the menu that will contain the new menu command by invoking the AVMenubarAcquireMenuByName method and passing the following arguments:

    • An AVmenubar object that represents the menu bar.

    • The name of the menu. For example, to reference the File menu, specify File.

This method returns an AVMenu object that corresponds to the specified menu name.

   AVMenu
FileMenu = AVmenubarAcquireMenuByName (Themenubar, "File");

If the menu does not exist, you can programmatically create it (see the next step).

  1. If necessary, programmatically create a new menu by invoking the AVMenuNew method and passing the following arguments:

The AVMenuNew method returns an instance of AVMenu.

AVMenu NewMenu = AVMenuNew ("Acrobat SDK", "ADBE:Acrobat_SDK",
 gExtensionID);

After you create a new menu, you must attach it to the menu bar. (See Adding a menu command to a new menu.)

  1. Create a new menu command by invoking the AVMenuItemNew method and passing the following arguments:

    • A string value that represents the menu command’s text. On Windows only, you can specify a keyboard shortcut by including an ampersand character (&) in the title.[I wonder whether an example would help here.] In Acrobat or Adobe Reader, an underscore character (_) is placed under the character following the ampersand ( char ).[I wonder whether an example would help here.] The user can then press alt+ char to select the item.

    • The language-independent name of the menu command to create. (See Using plugin prefixes.)

    • An AVMenu object that represents a submenu for which this menu command is the parent. Pass null if this menu item does not have a submenu.

    • A Boolean value. If true, the menu item is visible only when the user selects Full Menus. If false, the menu item is visible for both Full Menus and Short Menus modes. This value is ignored in Adobe Reader or Acrobat 3.0 or later.

    • The key to use as a shortcut for the menu command (an ASCII character). Use NO_SHORTCUT if the menu command does not have a shortcut.

    • Modifier keys, if any, that are used as part of the shortcut. Must be an OR of the Modifier Keys values, except that AV_COMMAND cannot be specified.

    • An AVIcon object that represents the icon to show in the menu command, or null if no icon is shown. In Windows, a valid icon is a 24x24 sample monochrome HBITMAP. In Mac OS, an icon is a handle to a standard SICN resource. For information about creating an AVIcon object, see Creating toolbar buttons.

    • An ASExtension value that registers this menu command. For information about an ASExtension value, see the Acrobat and PDF Library API Reference.

The AVMenuItemNew method returns an AVMenuItem object.

       AVMenuItem
menuItem = AVMenuItemNew ("Show Message", "ADBE:ExternWin",
      NULL, true, NO_SHORTCUT, 0, NULL, gExtensionID);
  1. Attach the menu command to a menu by invoking the AVMenuAddMenuItem method and passing the following arguments:

    • An AVMenu object to which a menu command is attached.

    • An AVMenuItem object that is attached.

    • The location in the menu that specifies where the command is added. You can specify APPEND_MENUITEM to append the menu command to the end of the menu.

If this method is successful, the menu command is added to the specified menu.

       AVMenuAddMenuItem (
FileMenu, menuItem, APPEND_MENUITEM);

#6 Release the typedef instances to free memory. To release an AVMenu instance, invoke the AVMenuRelease method and pass the AVMenu instance. To release an AVMenuItem instance, invoke the AVMenuItemRelease method and pass the AVMenuItem instance.

Adding a menu command to an existing menu

The following code example creates a new menu command that displays the text Show Message and attaches it to the File menu.

  1. Adding a menu command to an existing menu

//Declare menu variables
   AVMenubar Themenubar = NULL;
   AVMenu FileMenu = NULL;
   AVMenuItem NewMenuCommand = NULL;

//Retrieve the menu bar in Adobe Reader or Acrobat
   Themenubar = AVAppGetMenubar();

//Retrieve the File menu`
   FileMenu = AVMenubarAcquireMenuByName(Themenubar, "File");

//Create a new menu command
   NewMenuCommand = AVMenuItemNew("Show Message", "ADBE:ExternWin", NULL,

   true, NO_SHORTCUT, 0, NULL, gExtensionID);
   if (NewMenuCommand == NULL)
   {
   AVAlertNote ("Unable to create the menu command");
   AVMenuItemRelease(NewMenuCommand);
   return;
   }
//Attach the new menu command to the File menu
   AVMenuAddMenuItem (FileMenu, NewMenuCommand, APPEND_MENUITEM);

//Release the typedef instances
   AVMenuItemRelease(NewMenuCommand);
   AVMenuRelease(FileMenu);

Note

This code example creates a new menu command that displays Show Message in the File menu. However, before the menu command performs an action, you have to create a callback menu function. (See Creating menu callback functions.)

Tip

To see how the global gEntensionID variable is declared, see the plugin samples that accompany the Acrobat SDK.

Adding a menu command to a new menu

The following code example creates a new menu command that displays the text Show Message and attaches it to a new menu. The new menu is attached to the menu bar by invoking the AVmenubarAddMenu method.

//Declare menu variables
   AVMenubar Themenubar = NULL;
   AVMenu NewMenu = NULL;
   AVMenuItem NewMenuCommand = NULL;

//Retrieve the menu bar in Adobe Reader or Acrobat
   Themenubar = AVAppGetMenubar();

//Create a new menu

   NewMenu = AVMenuNew("New Menu", "ADBE:NewMenu", gExtensionID);
   if (NewMenu == NULL)
   {
   AVAlertNote ("Unable to create the menu");
   AVMenuRelease (NewMenu);
   return ;
   }

//Create a new menu command
   NewMenuCommand = AVMenuItemNew("Show Message", "ADBE:ExternWin", NULL,
   true, NO_SHORTCUT, 0, NULL, gExtensionID);
   if (NewMenuCommand == NULL)
   {
   AVAlertNote ("Unable to create the menu command");
   AVMenuItemRelease(NewMenuCommand);
   return;
   }

//Attach the menu item to the menu and the menu to

//the menu bar
   AVMenuAddMenuItem (NewMenu, NewMenuCommand, 0);
   AVMenubarAddMenu (Themenubar, NewMenu, APPEND_MENU);

//Release the typedef instances
   AVMenuItemRelease(NewMenuCommand);
   AVMenuRelease(NewMenu);

Note

If you plan to add a submenu to a menu command, you must create the submenu before creating the menu command.

Creating menu callback functions

When creating menus, you must create menu callback functions that are invoked by Adobe Reader or Acrobat. These types of callback functions can be created:

  • Execute: Invoked by Adobe Reader or Acrobat in response to a user selecting a menu command. This callback is required.

  • Compute-enabled: This optional callback is invoked by Adobe Reader or Acrobat when determining whether to enable the menu command.

  • Compute-marked: This optional callback is invoked by Adobe Reader or Acrobat when determining whether the menu command should be checked.

For the purpose of this discussion, a simplistic user-defined function named ShowMessage is introduced. This method displays a message box by invoking the AVAlertNote method. The following code example shows the body of the ShowMessage function.

ACCB1 void ACCB2 ShowMessage (void* data)
 {
     AVAlertNote ("A menu command was selected.");
 }

The data parameter for this and the other callbacks can be used to maintain private data for the menu command. Notice that this user-defined function is declared using the ACCB1 and ACCB2 macros. (See Using callback functions.)

For each callback that you create, you declare pointers to callbacks that are defined in the Acrobat core API:

AVExecuteProc ExecProcPtr = NULL;
 AVComputeEnabledProc CompEnabledProcPtr = NULL;
 AVComputeMarkedProc CompMarkedProcPtr = NULL;

AVExecuteProc is a callback that you can create that is invoked by Acrobat or Adobe Reader when a user selects a menu item. AVComputeEnabledProc is a callback that you can create that is invoked by Adobe Reader or Acrobat when determining whether to enable the menu command. AVComputeMarkedProc is a callback that you can create that is invoked by Adobe Reader or Acrobat when determining whether the menu command should be checked.

After you create a pointer, such as a pointer that points to AVExecuteProc, you can invoke the ASCallbackCreateProto macro that is defined in the Acrobat core API to convert a user-defined function to an Acrobat callback function. For example, you can invoke ASCallbackCreateProto to convert ShowMessage to a callback function. The ASCallbackCreateProto macro requires the following arguments:

  • The callback type. For example, you can pass AVExecuteProc.

  • The address of the user-defined function to convert to a callback function.

The ASCallbackCreateProto macro returns a callback of the specified type that invokes the user-defined function whose address was passed as the second argument. The following code example shows the ASCallbackCreateProto macro converting the ShowMessage user-defined function to a AVExecuteProc callback.

AVExecuteProc ExecProcPtr = NULL;
 ExecProcPtr = ASCallbackCreateProto(AVExecuteProc, &ShowMessage);

After you create an AVExecuteProc callback, invoke the AVMenuItemSetExecuteProc method to associate a menu command with a callback. That is, when a user selects a specific menu command, Acrobat or Adobe Reader will invoke the user-defined function whose address was passed to the ASCallbackCreateProto macro. The AVMenuItemSetExecuteProc method requires the following parameters:

  • An AVMenuItem instance that represents the menu command.

  • An AVExecuteProc that represents the callback function.

  • The address of a user-defined data structure that can be passed to the user-defined function.

When you are done with a menu callback, you can invoke the ASCallbackDestroy method to release memory that it consumes. The following code example creates callback functions for menu commands.

   /* Display a message box */
   ACCB1 void ACCB2 ShowMessage (void* data)
   {
   AVAlertNote ("A menu command was selected.");
   }
   ACCB1 ASBool ACCB2 ComputeMarkedProc (void* data)
   {
   ASBool expressionorcondition = true;
   if (expressionorcondition)
         return true;
   else return false;
   }
   ACCB1 ASBool ACCB2 ComputeEnabledProc (void* data)
   {
   if (AVAppGetNumDocs() > 0)
         return true;
   else return false;
   }
   ACCB1 ASBool ACCB2 PluginInit (void)
   {

//Declare menu callbacks
   AVExecuteProc ExecProcPtr = NULL;
   AVComputeEnabledProc CompEnabledProcPtr = NULL;
   AVComputeMarkedProc CompMarkedProcPtr = NULL;

//Declare menu variables
   AVMenu FileMenu = NULL;
   AVMenuItem NewItem = NULL;


//Retrieve the menu bar in Adobe Reader or Acrobat
   AVMenubar Themenubar = AVAppGetMenubar ();

//Create menu callbacks
   ExecProcPtr = ASCallbackCreateProto (AVExecuteProc, &ShowMessage);
   CompEnabledProcPtr = ASCallbackCreateProto (AVComputeEnabledProc,
   &ComputeEnabledProc);
   CompMarkedProcPtr = ASCallbackCreateProto (AVComputeMarkedProc,
   &ComputeMarkedProc);

//Retrieve the File menu
   FileMenu = AVmenubarAcquireMenuByName (Themenubar, "File");
   if (FileMenu)
   {

//Create a new menu item
   NewItem = AVMenuItemNew ("Show Message", "ADBE:ExternWin", NULL, true,
   NO_SHORTCUT, 0, NULL, gExtensionID);
   if (NewItem == NULL)
   {
         AVAlertNote ("Unable to create a menu item, not loading.");
         return false;
   }
   AVMenuItemSetExecuteProc (NewItem, ExecProcPtr, NULL);
   AVMenuItemSetComputeEnabledProc (NewItem,
   CompEnabledProcPtr,NULL);
   AVMenuItemSetComputeMarkedProc (NewItem,
   CompMarkedProcPtr,NULL);
   AVMenuAddMenuItem (FileMenu, NewItem, 1);
   AVMenuRelease (FileMenu);
   return true;
   }
   else return false;
   }
   ACCB1 ASBool ACCB2 PluginUnload (void)
   {
   ASCallbackDestroy (ExecProcPtr);
   ASCallbackDestroy (CompEnabledProcPtr);
   ASCallbackDestroy (CompMarkedProcPtr);
   return true;
   }

Note

Notice that the application logic that creates a menu command is located in the PluginInit procedure. (See Plugin loading and initialization.)

Determining if a menu item can be executed

In previous versions of Adobe Reader and Acrobat, it was possible for a document to execute a menu item in the viewing application using a Named action or the app.execMenuItem JavaScript method. These two features, referred to as ExecMenu expose all menu items to the document, potentially allowing a malicious document to compromise a user’s privacy or system. For example, it was possible to use the app.execMenuItem JavaScript method to obtain data from a document by creating the equivalent to a user selecting the menu sequence of Select All, Copy, and Paste.

Acrobat and Adobe Reader 8.0 and later contain a list of menu items that can be executed using ExecMenu. Any menu item not on the list cannot be programmatically executed.

You can determine if a menu item can be programmatically executed by invoking the AVMenuItemIsScriptable method and passing an AVMenuItem. This method returns a Boolean value. That is, if the menu item that corresponds to the AVMenuItem argument can be executed, True is returned; otherwise, False is returned.