There is a considerable amount of information online about how to add a custom form to the Additional menu in a form’s menu bar in Dynamics GP:

IvItemMainenanceForm.AddMenuHandler(new EventHandler(OpenInventoryManager), “Inventory Manager”);

But there are far fewer references instructing how to add a custom menu item to the cards items list in Dynamics GP:

In order to add a form from a .NET add-in to these menus, you will need to use the Menus for Visual Studio Tools add-in. This tool provides classes and methods for associating forms to menu items. Let’s look at the methods (and the code below) needed to add an item to a menu.

//menu for VS Tools section
// Application Name

const string APPNAME = “VSTMenusCSharp”;

// Dictionary ID Constants
const short DYNAMICS = 0;

// Shortcut Key Modifier Constants
const int COMMAND_SHORTCUT_CTRL = 65536;
const int COMMAND_SHORTCUT_CTRLSHIFT = 327680;
const int COMMAND_SHORTCUT_CTRLALT = 196608;
const int COMMAND_SHORTCUT_ALT = 131072;
const int COMMAND_SHORTCUT_ALTSHIFT = 393216;
const int COMMAND_SHORTCUT_CTRLALTSHIFT = 458752;

// Shortcut Key Function Key Constants, can be used instead of ASCII value
const short COMMAND_SHORTCUT_KEY_F1 = 112;
const short COMMAND_SHORTCUT_KEY_F2 = 113;
const short COMMAND_SHORTCUT_KEY_F3 = 114;
const short COMMAND_SHORTCUT_KEY_F4 = 115;
const short COMMAND_SHORTCUT_KEY_F5 = 116;
const short COMMAND_SHORTCUT_KEY_F6 = 117;
const short COMMAND_SHORTCUT_KEY_F7 = 118;
const short COMMAND_SHORTCUT_KEY_F8 = 119;
const short COMMAND_SHORTCUT_KEY_F9 = 120;
const short COMMAND_SHORTCUT_KEY_F10 = 121;
const short COMMAND_SHORTCUT_KEY_F11 = 122;
const short COMMAND_SHORTCUT_KEY_F12 = 123;

short MenuListTag1; short MenuTag1;
short MenuTag2;
short MenuTag3;
short MenuTag4;

public void Initialize()
{
// Register Event to add menu entries
MenusForVisualStudioTools. Functions.EventRegister.InvokeAfterOriginal += new EventRegisterFunction.InvokeEventHandler(VSTMCommandFormRegister);

// Register Event to handle callbacks from menu entries
MenusForVisualStudioTools. Functions.EventHandler.InvokeAfterOriginal += new EventHandlerFunction.InvokeEventHandler(VSTMCommandFormCallback);
}

void VSTMCommandFormRegister(object sender, EventRegisterFunction.InvokeEventArgs e)
{
short ParentTag = 0;
short BelowTag = 0;
short ResID = 0;

try
{
// Get Parent Tag for command list to add menu to
ParentTag = MenusForVisualStudioTools.Functions.GetTagByName.Invoke(
DYNAMICS, “Command_Inventory”, “CL_Inventory_Utilities”); // Dictionary ID, Form Name, Command Name
if (ParentTag <= 0) { throw new Exception(“Parent GetTagByName, error code: “ + Convert.ToString(ParentTag));
}

// Get Below Tag for command/command list to add menu below
BelowTag = MenusForVisualStudioTools.Functions.GetTagByName.Invoke(
DYNAMICS, “Command_Inventory”, “CL_Inventory_Utilities”); // Dictionary ID, Form Name, Command Name
if (BelowTag <= 0) { throw new Exception(“Below GetTagByName, error code: “ + Convert.ToString(BelowTag));
}

// Get Security Form Resource ID for menus to inherit security access from
ResID = MenusForVisualStudioTools.Functions.GetFormResId.Invoke(
DYNAMICS, “IV_Reconcile”); // Get Form Resource ID for Security
if (ResID <= 0) { throw new Exception(“GetFormResId, error code: “ + Convert.ToString(ResID));
}

MenuTag1 = MenusForVisualStudioTools.Functions.RegisterWithSecurity.Invoke(
ParentTag, // Parent Command Tag
“Inventory Manager”, // Menu Caption
“Click to open Inventory Manager”, // Menu Tooltip
0, 0, // Menu Shortcut Key, Shortcut Modifier
true, false, false, // Checked, Disabled, Hidden
BelowTag, // Add Below Command Tag
false, false, // Add Separator, Add Command List
DYNAMICS, ResID); // Security Dictionary and Form Resource ID

if (MenuTag1 <= 0) { throw new Exception(“Command 1 RegisterWithSecurity, error code: “ + Convert.ToString(MenuTag1));
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message, APPNAME);
}
}

void VSTMCommandFormCallback(object sender, EventHandlerFunction.InvokeEventArgs e)
{
short Tag = 0;
// Get Callback Tag Number for menu entry
// Tag = MenusForVisualStudioTools.Functions.Callback.Invoke();

Tag = e.inParam1;

// Compare Tag Sequence Number with Menu Sequence obtained during registration
if (Tag == MenuTag1)
{
//Forms.ContractNumberSelect contractSelect = new Forms.ContractNumberSelect();
//contractSelect.ShowDialog();

inventoryManager.ShowDialog();
}
}

This seems complicated and confusing, and certainly can be, but there are really just a few things required to accomplish the goal of adding a form to the menu.

More or less, copying the code above (download the code snippet here) to your GPAddIn.cs file will get you most of the way there, but there are a few changes that need to be made to personalize it. The first item is the ParentTag.

The ParentTag object is the ID of the menu that you wish to place the new item into. If you want to add your custom form link to the Customer Cards menu, then you need to find the Form Name and Command Name. This can only be found in the table provided in the associated document that comes with the download for the Menus add-in. I have duplicated it below.

Top Level Menu Submenu Form Command
Tools* Command_System CL_Tools
Toole >> Setup Command_System CL_Setup
System Command_System CL_System_Setup
Company Command_System CL_Comapny_Setup
Posting Command_System CL_Posting_Setup
Financial Command_Financials CL_Financial_Setup
Sales Command_Sales CL_Sales_Setup
Purchasing Command_Purchasing CL_Purchasing_Setup
Inventory Command_Inventory CL_Inventory_Setup
Payroll Command_Payroll CL_Payroll_Setup
Tools >> Utilities Command_System CL_Utilities
System Command_System CL_System_Utilities
Company Command_System CL_Company_Utilities
Financials Command_Financials CL_Financial_Utilities
Sales Command_Sales CL_Sales_Utilities
Purchasing Command_Purchasing CL_Purchasing_Utilities
Inventory Command_Inventory CL_Inventory_Utilities
Payroll Command_Payroll CL_Payroll_Utilities
Tools >> Routines Command_System CL_Routines
Company Command_System CL_Company_Routines
Financial Command_Financial CL_Financial_Routines
Sales Command_Sales CL_Sales_Routines
Purchasing Command_Purchasing CL_Purchasing_Routines
Inventory Command_Inventory CL_Inventory_Routines
Payroll Command_Payroll CL_Payroll_Routines
Transactions Command_System CL_Transactions
Financial Command_Financial CL_Financial_Transactions
Sales Command_Sales CL_Sales_Transactions
Purchasing Command_Purchasing CL_Purchasing_Transactions
Inventory Command_Inventory CL_Inventory_Transactions
Payroll Command_Payroll CL_Payroll_Transactions
Inquiry Command_System CL_Inquiry
System Command_System CL_System_Inquiry
Financial Command_Financial CL_Financial_Inquiry
Sales Command_Sales CL_Sales_Inquiry
Purchasing Command_Purchasing CL_Purchasing_Inquiry
Inventory Command_Inventory CL_Inventory_Inquiry
Payroll Command_Payroll CL_Payroll_Inquiry
Reports Command_System CL_Reports
System Command_System CL_System_Reports
Company Command_Payroll CL_Company_Reports
Financial Command_Purchasing CL_Purchasing_Reports
Sales Command_Sales CL_Sales_Reports
Purchasing Command_Purchasing CL_Purchasing_Reports
Inventory Command_Inventory CL_Inventory_Reports
Payroll Command_Payroll CL_Payroll_Reports
Cards Command_System CL_Cards
System Command_System CL_System_Cards
Financial Command_Financial CL_Financial_Cards
Sales Command_Sales CL_Financial_Cards
Purchasing Command_Purchasing CL_Purchasing_Cards
Inventory Command_Inventory CL_Inventory_Cards
Payroll Command_Payroll CL_Payroll_Cards
Help* Command_System CL_Help

*We recommend not adding items directly to this top-level menu

So, again, if we wanted to add a menu item in Customer Cards, for example, we would need to use Sales Cards, because Customers is listed in the Sales top level menu. So the Form Name is Command_Sales and the Command Name is CL_Sales_Cards. This would be the only items modified in the ParentTag. So the ParentTag would look like this:

ParentTag = MenusForVisualStudioTools.Functions.GetTagByName.Invoke(DYNAMICS, “Command_Sales”, “CL_Sales_Cards”);

Similarly, the BelowTag must be modified.

BelowTag = MenusForVisualStudioTools.Functions.GetTagByName.Invoke(DYNAMICS, “Command_Sales”, “CL_Sales_Cards”);

An additional modification to the VSTMCommandFormRegister method is to alter the ResId Resource ID to tell the menu what level of security to associate with the new custom menu item. The ResId is the name of a form in GP with the same level of permissions to associate with the new form.

ResID = MenusForVisualStudioTools.Functions.GetFormResId.Invoke(DYNAMICS, “IV_Reconcile”);

You must define the new Menu item which can be done in the MenuTag1 (You can define more than one).

MenuTag1 = MenusForVisualStudioTools.Functions.RegisterWithSecurity.Invoke(
ParentTag, // Parent Command Tag
“Assign Customer”, // Menu Caption
“Click to Assign Customers to Salespeople”, // Menu Tooltip
0, 0, // Menu Shortcut Key, Shortcut Modifier
true, false, false, // Checked, Disabled, Hidden
BelowTag, // Add Below Command Tag
false, false, // Add Separator, Add Command List
DYNAMICS, ResID); // Security Dictionary and Form Resource ID

The important items here are the Menu Caption and the Menu Tooltip. I have modified them in the above example to reflect a custom form that allows the user to assign specific customers to a salesperson.

The last required action is taken within the VSTMCommandFormCallback method. Here is where you define the form to open (or any other actions to be taken) when the new custom menu item is clicked. If, for example, our Assign Customers form class was named AssignCustomers.cs, then we could instantiate the new form here (unless it is defined the GPAddIn.cs class) and call it.

void VSTMCommandFormCallback(object sender, EventHandlerFunction.InvokeEventArgs e)
{
short Tag = 0;
// Get Callback Tag Number for menu entry
// Tag = MenusForVisualStudioTools.Functions.Callback.Invoke();

Tag = e.inParam1;

// Compare Tag Sequence Number with Menu Sequence obtained during registration
if (Tag == MenuTag1)
{
//Forms.ContractNumberSelect contractSelect = new Forms.ContractNumberSelect();
//contractSelect.ShowDialog();

AssignCustomers assignCustomers = new AssignCustomers();
assignCustomers.ShowDialog();
}

Happy customizing!

Feel free to reach out should you have questions or need assistance customizing Microsoft Dynamics GP.

Written by:
Aaron Rumford,
Consultant FMT Consultants