data-id=understanding-plugins
data-id=id1

Understanding Plugins

data-id=about-plugin-initialization
data-id=plugin-loading-and-initialization
data-id=id2

Plugin loading and initialization

When Acrobat or Adobe Reader is started, it searches the plugins directory (co-located with the Acrobat executable) to locate and load plugins. In addition, Acrobat or Adobe Reader searches folders that may be located within this folder. This search goes one level deep.

Acrobat and Adobe Reader display a progress message in the bottom line of the splash screen at start-up. As each plugin is loaded, the progress message shows the plugin name. No plugins are loaded if the Shift key is held down while Acrobat or Adobe Reader start. Also, if Acrobat or Adobe Reader are running in certified mode, no third-party plugins are loaded.

When creating methods for your plugin, keep the following rule in mind:

Implement PluginUnload procedure: This procedure frees allocated memory. This routine is invoked if any of the initialization routines returns false. Under normal conditions, this procedure is not invoked until the user closes Acrobat or Adobe Reader.

data-id=handshaking
data-id=id3

Handshaking

Acrobat and Adobe Reader perform a handshake with each plugin as it is opened and loaded. During handshaking, the plugin specifies its name, several initialization procedures, and an optional unload procedure.

A plugin must implement the following handshaking function:

ACCB1 ASBool ACCB2 PIHandshake(ASUns32 handshakeVersion, void, *hsData)

During handshaking, the plugin receives the hsData data structure (defined in the PIVersn.h file). Acrobat and Adobe Reader convert all function pointers that are passed in this data structure into callbacks using the ASCallbackCreateProto method. For information about this method, see the Acrobat and PDF Library API Reference.

The DUCallbacks.h header file declares all callback methods that must be located in your plugin. The following shows the function signatures of these callback methods:

ACCB1 ASBool ACCB2 PluginExportHFTs(void);
ACCB1 ASBool ACCB2 PluginImportReplaceAndRegister(void);
ACCB1 ASBool ACCB2 PluginInit(void);
ACCB1 ASBool ACCB2 PluginUnload(void);

All callbacks return true if your plugin’s procedure completes successfully or if the callbacks are optional and are not implemented. If your plugin’s procedure fails, it returns false. If either Acrobat, Adobe Reader, or a plug-in aborts handshaking, Acrobat or Adobe Reader displays an alert dialog box showing a brief explanation before loading other plugins. At minimum, a plugin must implement the PluginInit callback.

To ensure your plugin does not hinder Acrobat startup, you must limit code executed in your handshake functions to the minimum.

Note

The handshaking function is located in the PIMain.c file. This source code located in this file is functional and must not be modified.

The following example shows how a plugin’s PIHandshake method specifies the plugin callbacks provided during handshake and initialization. The tasks performed by each function is described in the next sections. For general information about creating callback functions, see Using callback functions.

ACCB1 ASBool ACCB2 PIHandshake(Uns32 handshakeVersion, void *handshakeData)
{
  if(handshakeVersion == HANDSHAKE_V0200)
  {
      PIHandshakeData_V0200 *hsData = (PIHandshakeData_V0200 *)handshakeData;
      hsData->extensionName = GetExtensionName();
      hsData->exportHFTsCallback =
          (void*)ASCallbackCreateProto(PIExportHFTsProcType,
              &PluginExportHFTs);
      hsData->importReplaceAndRegisterCallback =
          (void*)ASCallbackCreateProto(PIImportReplaceAndRegisterProcType,
              &PluginImportReplaceAndRegister);
      hsData->initCallback =
          (void*)ASCallbackCreateProto(PIInitProcType, &PluginLoad);
      hsData->unloadCallback =
          (void*)ASCallbackCreateProto(PIUnloadProcType, &PluginUnload);
      return true;
  }
  return false;
}
data-id=exporting-hfts
data-id=id4

Exporting HFTs

A Host Function Table (HFT) is the mechanism through which plugins invoke methods in Adobe Reader or Acrobat, as well as in other plugins. After Acrobat finishes handshaking with all the plugins, it invokes each plug-in’s PluginExportHFTs callback procedure.

In the PluginExportHFTs procedure, a plugin may export any HFTs it intends to make available to other plugins. This callback should only export an HFT, not invoke other Acrobat core API methods. (See Working with Host Function Tables.)

Note

The only time a plugin can export an HFT is during execution of its PluginExportHFTs procedure.

data-id=importing-hfts-and-registering-for-notifications
data-id=id5

Importing HFTs and registering for notifications

After Acrobat or Adobe Reader completes invoking each plugin’s PluginExportHFTs callback method, it invokes each plugin’s PluginImportReplaceAndRegister callback method. In this method, plugins perform three tasks:

  1. Import any special HFTs they use (the standard Acrobat HFTs are automatically imported). Plugins also may import HFTs any time after this while the plugin is running.
  2. Register for notifications by using the AVAppRegisterNotification method. Plugins also may register and unregister for notifications while the plugin is running. A plugin may receive a notification any time after it has registered for it, even if the plugin’s initialization callback has not yet been called. This can occur if another plugin initializes first and performs an operation, such as creating a PDF document, which causes a notification to be sent. Plugins must be prepared to correctly handle notifications as soon as they register for them.
  3. Replace any of the Acrobat API’s replaceable HFT methods. (See Replacing HFT methods.)

Note

The only time a plugin may import an HFT or replace a standard API method is within its PluginExportHFTs callback procedure. Plugins may register for notifications at this time or any time afterward.

data-id=initialization
data-id=id6

Initialization

After Acrobat or Adobe Reader completes calling each plugin’s PluginImportReplaceAndRegister callback method, it invokes each plugin’s PluginInit procedure. Plugins can use their initialization procedures to hook into Acrobat’s user interface by adding menu items, toolbar buttons, windows, and so on. It is also acceptable to modify Acrobat’s user interface later when the plugin is running.

When creating the initialization portion of a plugin, keep the following rules in mind:

Avoid creating dialog boxes: Do not create a dialog box in your plugin’s initialization or do anything else that may interfere with the successful startup of Acrobat or Adobe Reader. The application may be started by using an interapplication communication (IAC) event, in which case a user would not be present to respond to your dialog box.

Avoid invoking methods that cause Acrobat to load non-critical components: Here are actions your plugin should avoid, listed in order of importance:

Note

Non-Adobe plugins are fully initialized during Acrobat startup. Invoking functions declared in HFTs exported by non-Adobe plugins will not significantly delay Acrobat startup, unless those plugins violate the principles listed here.

Do create your menu items: Creating your menu items during initialization ensures that your menu items will be available in any PDF document opened using Acrobat or Adobe Reader.

If your plugin must carry out a task after all plugins are initialized, it should register for the AVAppDidInitialize notification. This notification is invoked when Acrobat finishes initializing and is about to enter its event loop.

data-id=unloading
data-id=id7

Unloading

A plugin’s PluginUnload procedure should free any memory the plugin allocated and remove any user interface changes it made. Acrobat invokes this procedure when it terminates or when any of the other handshaking callbacks return false. This function should perform the following tasks:

Currently, plugins unload only when Acrobat exits.

data-id=summarizing-a-plugin-s-life-cycle
data-id=id8

Summarizing a plugin’s life cycle

The following steps describe the life cycle of a plugin:

  1. At startup, Adobe Reader or Acrobat searches its plugin directory for plugin files.

  2. For each plugin file, Adobe Reader or Acrobat attempts to load the file. If the plugin is successfully loaded, Adobe Reader or Acrobat invokes routines in PIMain.c that complete the handshaking process.

  3. Adobe Reader or Acrobat invokes callback functions in this order:

    • PluginExportHFTs
    • PluginImportReplaceAndRegister
    • PluginInit

This sequence establishes the linkages between the plugin and Acrobat or Adobe Reader, and between the plugin and any other plugins. After all plugins are loaded, Acrobat or Adobe Reader continues its own loading and starts the user interface. It adds plugin tools to the toolbar, and plugin menu items to the menu bar. Then it starts the user session.

data-id=using-callback-functions
data-id=id9

Using callback functions

Acrobat or Adobe Reader invokes callback functions that you define to perform a specific task. For example, when a user clicks a button located on a toolbar, a callback method is invoked. (See Creating toolbar button callback functions.)

To create a callback function, you can invoke the ASCallbackCreateProto, ASCallbackCreateReplacement, and ASCallbackCreateNotification methods to convert functions into callback functions and to perform type checking. This enables the compiler to determine whether the correct prototypes are used for a specific callback function. For information about these methods, see the Acrobat and PDF Library API Reference.

Type checking only occurs if the DEBUG macro is set to 1 at the time your plug-in is compiled. Be sure to set it appropriately in your development environment and remove it when you build the shipping version of your plugin.

The following code example shows the syntax to create a callback function:

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

The ASCallbackCreateProto macro returns a callback of the specified type that invokes the user-defined function whose address is passed as the second argument. In this example, the ShowMessage function is converted to a callback function (the ShowMessage function is a user-defined function that is invoked when a specific action occurs).

The ASCallbackCreateProto macro returns a pointer to a function that can be invoked by a plugin or by Acrobat or Adobe Reader. Use the ASCallbackDestroy method to dispose of a callback that is no longer required.

All callbacks must be declared with Pascal calling conventions. To make your code portable between platforms, declare all your callback functions using the ACCB1 and ACCB2 macros:

static ACCB1 const char* ACCB2 ShowMessage(Thing* foo);
data-id=notifications
data-id=id10

Notifications

The Acrobat core API provides a notification mechanism so that plugins can synchronize their actions with Acrobat or Adobe Reader. Notifications enable a plugin to indicate that it has an interest in a specified event, such as an annotation being modified, and to provide a procedure that Acrobat invokes each time that event occurs. (See Registering for Event Notifications.)

data-id=handling-events
data-id=id11

Handling events

You can use the Acrobat core API to handle various types of events.

data-id=mouse-clicks
data-id=id12

Mouse clicks

Mouse clicks are passed to any procedure registered using the AVAppRegisterForPageViewClicks method. If all of those procedures return false, the click is passed to the active tool. If that returns false, the click is passed to any annotation at the current location.

You can query the state of the mouse buttons in a manner appropriate for drag operations by invoking the AVSysTrackMouse method. (See the Acrobat and PDF Library API Reference.)

data-id=adjust-cursor
data-id=id13

Adjust cursor

Adjust cursor events are passed to any procedures registered using the AVAppRegisterForPageViewAdjustCursor method. If all of those procedures return false, the event is passed to the active tool. If that returns false, the event is passed to any annotation at the current location.

data-id=key-presses
data-id=id14

Key presses

Key presses are first passed to the currently active selection server. If the selection server’s AVDocSelectionKeyDownProc callback returns false, Acrobat or Adobe Reader handles special keys (Esc, Page Up, Page Down) or uses the key to select a tool from the toolbar.

data-id=using-plugin-prefixes
data-id=id15

Using plugin prefixes

It is important to correctly name all items located in your plugin, such as HFTs, menus, toolbars, and so on, to ensure they function properly. Failure to do so may cause your plugin to produce unpredictable results when your plugin collides with a plugin of another developer who used the same names.

Prevent spaces from being used in tokens you intend to use as names in a PDF file. This can happen, for example, if you allow a user to type a name into the PDF file and your plugin does not check the input before writing it to the file.

data-id=obtaining-a-developer-pdf-name-prefix
data-id=id16

Obtaining a developer PDF name prefix

In support of ISO 32000, Adobe maintains a list of the prefixes of second class names for PDF. It is freely open to all developers and organizations following the specifications given in Annex E of ISO 32000. For example, Adobe uses ADBE or Acro. This chapter uses ADBE in the examples. Your plugins will use your unique PDF name. Register your name at https://github.com/adobe/pdf-names-list.

Note

Registering a PDF name ensures that you name is unique. It is up to you to ensure that names are unique among all plugins you or your company write (for example, you must ensure that two of your plugins do not both use ADBE_save as a menu item name).

data-id=using-a-developer-prefix
data-id=id17

Using a developer prefix

Every plugin must use the prefix to name its various elements as well as private data it writes into PDF documents. The following sections describe and provide an example of each element that must use a prefix.

data-id=plugin-name
data-id=id18

Plugin name

ExtensionName, used in plugin handshaking, must use the following syntax: Prefix_PluginName.

hsData->extensionName = ASAtomFromString("ADBE_SuperCrop");
data-id=menu-prefixes
data-id=id19

Menu names must use the following syntax: Prefix:MenuName.

SuperCropMenu = AVMenuNew(SuperCrop, "ADBE:SuperCropMenu", gExtensionID);

For information about invoking the AVMenuNew method, see Adding menu commands to menus.

data-id=menu-items-prefixes
data-id=id20

Menu item names must use the following syntax: Prefix:MenuItem.

SelSuperCropTool = AVMenuItemNew(SuperCrop, "ADBE:SuperCropMItem", NULL,
 false, '9', AV_OPTION, SuperCropIcon, gExtensionID);
data-id=tool-prefixes
data-id=id21

Tool prefixes

Tools names must use the following syntax: Prefix:Tool.

static ACCB1 ASAtom ACCB2 SuperCropToolGetType(AVTool tool)
 {
     return ASAtomFromString("ADBE:SuperCropTool");
 }
data-id=toolbar-button-prefixes
data-id=id22

Toolbar button prefixes

Toolbar buttons must use the following syntax: Prefix:ToolbarButton.

myButton = AVToolButtonNew(ASAtomFromString("ADBE:HelloWorld"), (void *)
 myBM, false, false);

For information about creating a toolbar button, see Creating toolbar buttons.

data-id=private-data-id-d-via-second-class-names
data-id=id23

Private data ID’d via second-class names

If you add private data to keys defined in a Cos dictionary and you want the document to be readable to others outside your company, you must identify the data using second-class names. Such key names use the syntax Prefix_PrivateDataName, where Prefix identifies the company or other entity that introduces the key, and PrivateDataName identifies the data.

When adding keys that are directly referenced from private keys, it is not necessary to use the developer prefix. In the following example, the keys named First and Second cannot be referenced from any object in the PDF file except the private key that uses an appropriate prefix. Therefore, there is no need to use a prefix for the latter two keys.

/ACME_aName << /First 2 /Second << /Third [ 2 3 ] >> >>

Note

For information about Cos dictionaries, such as the one shown in the previous example, see Working with Cos dictionaries.

data-id=action-prefixes
data-id=id24

Action prefixes

Actions must use the following syntax: Prefix_ActionName.

AVAppRegisterActionHandler(&BkmkHandler, NULL, "ADBE_HWAction", "HWAct");
data-id=annotation-prefixes
data-id=id25

Annotation prefixes

Annotation prefixes must use the following syntax: Prefix_AnnotType.

return(ASAtomFromString("ADBE_MarkUpAnnot");
data-id=hft-prefixes
data-id=id26

HFT prefixes

When your plugin exposes any HFTs of its own, it must use an HFT name that conforms to the following syntax: Prefix_HFTName.

gDebuggWinHFTServer =
 HFTServerNew("ADBE_DebugWin",provideDebugWinHFTCallback, NULL, NULL);

For information about HFTs, see Working with Host Function Tables.

data-id=modifying-the-acrobat-or-adobe-reader-user-interface
data-id=id27

Modifying the Acrobat or Adobe Reader user interface

This section describes typical operations that a plugin can perform to modify the Acrobat or Adobe Reader user interface. To modify the user interface, you must invoke methods that belong to the Acrobat Viewer Layer. As a result, you cannot modify the Acrobat or Adobe Reader user interface by using the PDF Library API. (See Acrobat Viewer layer.)

data-id=adding-or-removing-menus-and-menu-items
data-id=id28

Adding or removing menus and menu items

You can use the Acrobat core API to add new menus and add commands to existing menus. You can also remove a menu or a menu command.

Menu commands can have shortcuts (keyboard accelerators). Acrobat and Adobe Reader do not ensure that plugins add unique shortcuts, but it is possible to programmatic-ally check which shortcuts are already in use before adding them.

You are encouraged to have your plugin add its menu commands to the Tools menu. When the plugin starts, Acrobat or Adobe Reader automatically adds this menu, as well as the About Plugins and Plugin Help menus. After Acrobat or Adobe Reader loads all plugins, it checks these three menus and removes any that are empty. (See Creating Menus and Menu Commands.)

data-id=modifying-toolbars
data-id=id29

Modifying toolbars

You can add new buttons to the toolbar, although the size and resolution of the user’s monitor can limit the number of tool buttons that are displayed. You can also remove buttons from an existing toolbar. (See Creating Toolbars and Buttons.)

data-id=controlling-the-about-box-and-splash-screen
data-id=id30

Controlling the About box and splash screen

You can set values in the preferences file by invoking the AVAppSetPreference method to prevent the Acrobat or Adobe Reader About box or splash screen from appearing before displaying the first document. These changes take effect the next time Acrobat or Adobe Reader is started.

About Adobe Plugins is a standard menu command in the Help menu. This menu command contains a submenu. You are encouraged to have your plugin add a menu command to the submenu to bring up its own About box.

data-id=creating-help-files
data-id=id31

Creating help files

The Help directory that accompanies Acrobat or Adobe Reader provides a standard location for your plug-in help files. You can place a help file either in the Help directory or in a subdirectory of the Help directory. If, for example, your plugin is localized for Japanese, you may want to place its Japanese help file in a Help_JPN subdirectory. To help open locale-specific help files, the Acrobat core API provides the AVAppOpenHelpFile method. (See the Acrobat and PDF Library API Reference.)

data-id=user-interface-guidelines
data-id=id32

User interface guidelines

Follow these guidelines when modifying the Acrobat or Adobe Reader user interface:

data-id=acquiring-and-releasing-objects
data-id=id33

Acquiring and releasing objects

Ensure that calls to Acquire and Release methods match. Objects obtained by Acquire methods must ultimately be released. If they are not released, Acrobat or Adobe Reader raises exceptions when a non-zero reference count is discovered. An exception can occur when Acrobat or Adobe Reader quits or when a document is closed.

When allocating memory to objects, follow these guidelines:

If you use an Acquire method to obtain an object, you must subsequently use a Release method to correctly update the reference counter, as shown in the following example:

PDDoc doc;
PDPage page;

//Acquire a page from a PDF document
doc = PDDocOpenFromASFile("myPDF.pdf", null, true);
page = PDDocAcquirePage(doc, 42);

//Perform a task using the page
//Release the page
PDPageRelease (page);

Notice that the PDPage object is acquired by invoking the PDDocAcquirePage method and is released by invoking the PDPageRelease method. For information about working with pages, see Working with Page Views and Contents.

data-id=debugging-plugins
data-id=id34

Debugging plugins

When debugging your plugin, consider the following points:

data-id=page-view-layers
data-id=id35

Page view layers

Acrobat and Adobe Reader drawing and mouse click processing rely on the concept of page view layers, which are numbers of type ASFixed that are associated with the document itself and each annotation type.

The following table shows the predefined layers used by Acrobat and Adobe Reader.

Layer
Item
0
Page contents
LINK_LAYER (1)
Links
NOTE_LAYER (3)
Annotations, open and closed. Open annotations are drawn above closed annotations.

These layers are used in the following situations:

Drawing: The layers are drawn from lowest to highest. As indicated in the table, the page contents are drawn first, followed by links, closed annotations, and finally open annotations. As a result, open annotations are drawn over any closed annotations that they overlap.

Mouse click processing: Occurs from highest layer to lowest layer. When a mouse click occurs, it is first passed to any open text note at the mouse click’s location, then any closed text note, then any link, and finally to the page view itself. However, mouse clicks are passed to a lower layer only if a higher layer declines to handle the mouse click by returning false from its DoClick callback. (See Tool callbacks.)

Annotation handlers provided by plugins can reside in any layer. For example, a plugin could choose for its annotations to be between the page contents and links, such as in layer 0.5 (because layers are numbers of type ASFixed).

An annotation handler’s AVAnnotHandlerGetLayerProc callback is called during screen updates and mouse clicks to return its layer. Using a callback rather than a constant value allows an annotation’s layer to change. For example, Acrobat’s built-in text annotation changes its layer, allowing open text annotations to receive mouse clicks before closed annotations, if both are at the mouse click location (on the other hand, Acrobat’s built-in link annotation does not change its layer).

Note

Acrobat and Adobe Reader do not invoke AVAnnotHandlerGetLayerProc callbacks for changes in value, so be sure to invalidate the page rectangle of an annotation when its layer changes.

For information about page views, see Working with Page Views and Contents.

data-id=minimizing-screen-redrawing
data-id=id36

Minimizing screen redrawing

Minimize screen redrawing by using the AVPageViewBeginOperation and AVPageViewEndOperation methods to bracket any sequence of view changes you may perform. For example, the sequence of changing to another page, scrolling, and zooming would normally redraw the screen three times. But, by invoking the AVPageViewBeginOperation method before the sequence and the AVPageViewEndOperation method after it, only one redraw occurs.

data-id=storing-private-data-in-pdf-files
data-id=id37

Storing private data in PDF files

Plugins can store private data in PDF files, although private data must be stored in such a way that the file can still be drawn by Acrobat. Adobe maintains a registry of private PDF dictionary key names to reduce the possibility of a plugin’s key names conflicting with names belonging to other plugins. For information about dictionaries, see Working with Cos dictionaries.

Private dictionary keys exist in the following categories:

data-id=exporting-data-from-pdf-document-objects
data-id=id38

Exporting data from PDF document objects

Using the Acrobat core API, you can export data from PDF document objects to XML files. Object data contain property-value pairs. For example, consider a PDF document object that contains the following XML elements:

Node
Name
nodeTag
xyz_Node
nodeNameTag
xyz_NodeName
propTag
xyz_Property
propNameTag
xyz_PropertyName
propValTag
xyz_Value

After you export the data from this object into an XML file, the data would appear as shown in the following diagram.

[ExtractXML.png]

To retrieve data from a PDF document object, invoke the PDDocExportUserProperties method and pass the following arguments: