Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

Unable to see button added on edit toolbar using plugin

New Here ,
Sep 17, 2025 Sep 17, 2025

Hi,
I was building a plugin for acrobat pro that adds a button to the edit toolbar and the button calls a function to add annotation to the selected text. I am using the Basic Plugin as my base and making changes to the BasicPluginInit.cpp file. I tried to replicate what I saw in the documentation here-
https://opensource.adobe.com/dc-acrobat-sdk-docs/library/plugin/Plugins_Toolbutton.html
Unfortunately, even though my plugin builds and I place the .api file at the correct address I am not able to see any additional items on the edit toolbar.
Here is the code for my init.cpp file-

/*********************************************************************

 ADOBE SYSTEMS INCORPORATED
 Copyright (C) 1998-2006 Adobe Systems Incorporated
 All rights reserved.

 NOTICE: Adobe permits you to use, modify, and distribute this file
 in accordance with the terms of the Adobe license agreement
 accompanying it. If you have received this file from a source other
 than Adobe, then your use, modification, or distribution of it
 requires the prior written permission of Adobe.

 -------------------------------------------------------------------*/
/** 
 \file BasicPluginInit.cpp

 - Skeleton .cpp file for a plug-in. It implements the basic
   handshaking methods required for all plug-ins.
 - A convenient function is provided to add a menu item easily. 

*********************************************************************/

// Acrobat Headers.
#ifndef MAC_PLATFORM
#include "PIHeaders.h"
#endif

/*-------------------------------------------------------
	Constants/Declarations
-------------------------------------------------------*/
// stuff for Menu set up 
static AVMenuItem menuItem = NULL;
ACCB1 ASBool ACCB2 PluginMenuItem(char* MyMenuItemTitle, char* MyMenuItemName);

// callback functions implemented in file "BasicPlugin.cpp"
extern ACCB1 void ACCB2 MyPluginCommand(void *clientData);
extern ACCB1 ASBool ACCB2 MyPluginIsEnabled(void *clientData);
extern ACCB1 ASBool ACCB2 MyPluginSetmenu();
extern ACCB1 void ACCB2 AcroAppModeSwitchNotification(void* clientData);
extern const char* MyPluginExtensionName;

/*-------------------------------------------------------
	Annotation helper / toolbar additions
-------------------------------------------------------*/
// Global references for toolbar button and its callback so we can release during unload
static AVToolButton CreateAnnotButton = NULL;
static ASCallback gCreateAnnotExecCB = NULL; // store as ASCallback

// Forward declaration
static ACCB1 void ACCB2 CreateSampleAnnotExecute(void* clientData);

static void AddCreateAnnotationToolButton()
{
	const char* toolbarName = "UndoRedo"; 
	AVToolBar toolBar = AVAppGetToolBarByName(toolbarName);
	if (!toolBar)
		return;
	if (CreateAnnotButton)
		return;
	AVIcon icon = NULL; 

	CreateAnnotButton = AVToolButtonNew(ASAtomFromString("MyExtn:CreateAnnotButton"), icon, false, false);
	if (!CreateAnnotButton)
		return;
	gCreateAnnotExecCB = ASCallbackCreateProto(AVExecuteProc, &CreateSampleAnnotExecute);
	AVToolButtonSetExecuteProc(CreateAnnotButton, (AVExecuteProc)gCreateAnnotExecCB, NULL);
	AVToolBarAddButton(toolBar, CreateAnnotButton, false, NULL);
}

static void CreateSimpleTextAnnotation()
{
	AVDoc avDoc = AVAppGetActiveDoc();
	if (!avDoc) { AVAlertNote("No active document."); return; }
	PDDoc pdDoc = AVDocGetPDDoc(avDoc);
	PDPage page = PDDocAcquirePage(pdDoc, 0);
	DURING
	{
		ASFixedRect fr;
		fr.left = ASInt32ToFixed(36);
		fr.right = ASInt32ToFixed(136);
		fr.top = ASInt32ToFixed(792 - 36);
		fr.bottom = ASInt32ToFixed(792 - 136);
		PDAnnot annot = PDPageCreateAnnot(page, ASAtomFromString("Text"), &fr);
#ifdef CastToPDTextAnnot
		PDTextAnnot textAnnot = CastToPDTextAnnot(annot);
#else
		PDTextAnnot textAnnot = (PDTextAnnot)annot;
#endif
		const char* contents = "Created by toolbar button.";
		PDTextAnnotSetOpen(textAnnot, true);
		PDTextAnnotSetContents(textAnnot, contents, (ASInt32)strlen(contents));
		PDPageAddAnnot(page, -2, textAnnot);
		AVPageView pv = AVDocGetPageView(avDoc);
		if (pv) {
			AVRect devRect; ASFixedRect fixedRect = fr; AVPageViewRectToDevice(pv, &fixedRect, &devRect); AVPageViewInvalidateRect(pv, &devRect);
		}
	}
	HANDLER { AVAlertNote("Failed to create annotation (exception)."); }
	END_HANDLER
	PDPageRelease(page);
}

static ACCB1 void ACCB2 CreateSampleAnnotExecute(void* clientData)
{
	CreateSimpleTextAnnotation();
}

/*-------------------------------------------------------
	Core Handshake Callbacks
-------------------------------------------------------*/

/**
	Callback invoked by the application to give the plug-in an opportunity to register 
	an HFTServer with the application.
	@return true to indicate the plug-in should continue loading.
*/
ACCB1 ASBool ACCB2 PluginExportHFTs(void)
{
	return true;
}

/** 
	The application calls this function to allow it to
	<ul>
	<li> Import plug-in supplied HFTs.
	<li> Replace functions in the HFTs you're using (where allowed).
	<li> Register to receive notification events.
	</ul>
*/
ACCB1 ASBool ACCB2 PluginImportReplaceAndRegister(void)
{
	return true;
}

/** 
	The main initialization routine.
	We register our action handler with the application.
	@return true to continue loading the plug-in
	@return false to cause plug-in loading to stop.
*/
/* PluginInit
** ------------------------------------------------------
**
** The main initialization routine.
**
** Return true to continue loading plug-in.
** Return false to cause plug-in loading to stop.
*/
ACCB1 ASBool ACCB2 PluginInit(void)
{
	//Register for mode switch notification.
	AVAppRegisterNotification(AcroAppModeSwitchNSEL, gExtensionID,
		(void*)ASCallbackCreateNotification(AcroAppModeSwitch, AcroAppModeSwitchNotification), NULL);

	ASBool ok = MyPluginSetmenu();
	// Add our toolbar button after menus
	AddCreateAnnotationToolButton();
	return ok;
}

/** 
	The unload routine.
	Called when your plug-in is being unloaded when the application quits.
	Use this routine to release any system resources you may have
	allocated.

	Returning false will cause an alert to display that unloading failed.
	@return true to indicate the plug-in unloaded.
*/
ACCB1 ASBool ACCB2 PluginUnload(void)
{
	if (menuItem)
		AVMenuItemRemove(menuItem);
	if (gCreateAnnotExecCB)
		ASCallbackDestroy(gCreateAnnotExecCB);
	gCreateAnnotExecCB = NULL;
	CreateAnnotButton = NULL;
	return true;
}

/**
	Return the unique ASAtom associated with your plug-in.
	@return the plug-ins name as an ASAtom.
*/
ASAtom GetExtensionName()
{
	return ASAtomFromString(MyPluginExtensionName);
}



/**
	Function that provides the initial interface between your plug-in and the application.
	This function provides the callback functions to the application that allow it to 
	register the plug-in with the application environment.

	Required Plug-in handshaking routine: <b>Do not change it's name!</b>
	
	@param handshakeVersion the version this plug-in works with. There are two versions possible, the plug-in version 
	and the application version. The application calls the main entry point for this plug-in with its version.
	The main entry point will call this function with the version that is earliest. 
	@param handshakeData OUT the data structure used to provide the primary entry points for the plug-in. These
	entry points are used in registering the plug-in with the application and allowing the plug-in to register for 
	other plug-in services and offer its own.
	@return true to indicate success, false otherwise (the plug-in will not load).
*/
ACCB1 ASBool ACCB2 PIHandshake(Uns32 handshakeVersion, void *handshakeData)
{
	
	//Enable the below code in #if 0 to make this plugin Acrobat only.
#if 0
	char* product = (char*)ASGetConfiguration(ASAtomFromString("Product"));
	if(strcmp(product,"Reader") == 0)
		return false;
#endif

	if (handshakeVersion == HANDSHAKE_V0200) {
		/* Cast handshakeData to the appropriate type */
		PIHandshakeData_V0200 *hsData = (PIHandshakeData_V0200 *)handshakeData;

		/* Set the name we want to go by */
		hsData->extensionName = GetExtensionName();

		/* If you export your own HFT, do so in here */
		hsData->exportHFTsCallback = (void*)ASCallbackCreateProto(PIExportHFTsProcType, &PluginExportHFTs);

		/*
		** If you import plug-in HFTs, replace functionality, and/or want to register for notifications before
		** the user has a chance to do anything, do so in here.
		*/
		hsData->importReplaceAndRegisterCallback = (void*)ASCallbackCreateProto(PIImportReplaceAndRegisterProcType,
																					 &PluginImportReplaceAndRegister);

		/* Perform your plug-in's initialization in here */
		hsData->initCallback = (void*)ASCallbackCreateProto(PIInitProcType, &PluginInit);

		/* Perform any memory freeing or state saving on "quit" in here */
		hsData->unloadCallback = (void*)ASCallbackCreateProto(PIUnloadProcType, &PluginUnload);

		/* All done */
		return true;

	} /* Each time the handshake version changes, add a new "else if" branch */

	/*
	** If we reach here, then we were passed a handshake version number we don't know about.
	** This shouldn't ever happen since our main() routine chose the version number.
	*/
	return false;
}

/*-------------------------------------------------------
	Menu Utility
-------------------------------------------------------*/

/**
	A convenient function to add a menu item under Acrobat SDK menu.
	@param MyMenuItemTitle IN String for the menu item's title.
	@param MyMenuItemName IN String for the menu item's internal name.
	@return true if successful, false if failed.
	@see AVAppGetMenubar
	@see AVMenuItemNew
	@see AVMenuItemSetExecuteProc
	@see AVMenuItemSetComputeEnabledProc
	@see AVMenubarAcquireMenuItemByName
	@see AVMenubarAcquireMenuByName
*/
ACCB1 ASBool ACCB2 PluginMenuItem(char* MyMenuItemTitle, char* MyMenuItemName)
{
	AVMenubar menubar = AVAppGetMenubar();
	AVMenu volatile commonMenu = NULL;

	if (!menubar)
		return false;

	DURING

   		// Create our menuitem
		menuItem = AVMenuItemNew (MyMenuItemTitle, MyMenuItemName, NULL, true, NO_SHORTCUT, 0, NULL, gExtensionID);
		AVMenuItemSetExecuteProc (menuItem, ASCallbackCreateProto(AVExecuteProc, MyPluginCommand), NULL);
		AVMenuItemSetComputeEnabledProc (menuItem,
				ASCallbackCreateProto(AVComputeEnabledProc, MyPluginIsEnabled), (void *)pdPermEdit);

		commonMenu = AVMenubarAcquireMenuByName (menubar, "ADBE:Acrobat_SDK");
		// if "Acrobat SDK" menu is not existing, create one.
		if (!commonMenu) {
			commonMenu = AVMenuNew ("Acrobat SDK", "ADBE:Acrobat_SDK", gExtensionID);
			AVMenubarAddMenu(menubar, commonMenu, APPEND_MENU); 		
		}
		
		AVMenuAddMenuItem(commonMenu, menuItem, APPEND_MENUITEM);

		AVMenuRelease(commonMenu);

	HANDLER
		if (commonMenu)
			AVMenuRelease (commonMenu);
		return false;
	END_HANDLER

	return true;
}


I am expecting an item to show up here-

adhirath_7243_0-1758113134305.png


And I am able to see the plugin avalialble in the context menu-

adhirath_7243_1-1758113189493.png


Please let me know what I'm missing, Thanks!

TOPICS
Acrobat SDK and JavaScript , Windows
85
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 17, 2025 Sep 17, 2025

So first, where did you get the name of the toolbar?   I do not believe that "UndoRedo" is the name of the "Edit PDF" toolbar.  Did you step through the code to see if the call to "AVAppGetToolBarByName" returns null?  

Next, the change to the new interface changed how toolbars are handled. I'm pretty sure that random plug-ins are now restricted from adding menus or toolbuttons to built-in Acrobat items.    

After you've gotten the correct toolbar name, change Acrobat back to the old UI and see if the button gets added. 

 

Use the "AVAppGetLegacyToolBar" function to get a list of all toolbars. 

Here's the reference:

https://opensource.adobe.com/dc-acrobat-sdk-docs/acrobatsdk/apireference/index.html

 

 

 

Thom Parker - Software Developer at PDFScripting
Use the Acrobat JavaScript Reference early and often

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Sep 17, 2025 Sep 17, 2025

Hi @Thom Parker ,
I got the toolbar name from here-

adhirath_7243_0-1758176882110.png

Also how do I do the following-
1) change acrobat to older version
2) I am unable to debug as well, the project builds fine but when I run with debugger I get an error.
So what all functionalities from plugins are not aplicable to the new acrobat?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 18, 2025 Sep 18, 2025

Change to the old UI from the Hamburger menu. Here:

Acrobat64_DisableNew.jpg

 

 

The names in that table may be more applicable to the old Acrobat, than the new.  The equivalent names in the new UI are probably different. Also, the toolbar you are interested in is the "Advanced Editing" . 

 

Debug is pretty important, so you need to get that figured out. You'll also need to verify the UI items before continuing with anything else. So, until you get debug figured out. Write a test plug-in to display the info you need to figure out. Use the AVAlertNote() function.

 

 

Thom Parker - Software Developer at PDFScripting
Use the Acrobat JavaScript Reference early and often

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
20 hours ago 20 hours ago

Thanks this helped a lot! I ended up creating a new toolbar and adding buttons to it. I did want to understand if I can open a panel when the button in my toolbar is clicked(something like the comments panel). I would later like to embed a web browser through CEF to show up in this panel. Would appreciate any guidance that can be provided. Thanks!

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
5 hours ago 5 hours ago
LATEST

I've found that adding menu items and toolbar buttons to Acrobat's existing items can be problematic. Having your own toolbar is best. 

 

The connection between a plug-in and the Acrobat UI panels is tenous. A couple of the things you can do is to execute menu items that open such items, and use JavaScript to set the viewState object.   

 

 

 

 

Thom Parker - Software Developer at PDFScripting
Use the Acrobat JavaScript Reference early and often

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines