Surprisingly, many visitors are interested in writing XLL add-ins for Excel. Today, I want to describe a Delphi sample add-in which adds a custom menu to the menu bar. This sample applies to Excel 11 and before. The custom menu will appear in the Add-Ins tab of new releases of Excel.
You cannot use XLL add-ins to add items to the Ribbon UI. Please, read my article about COM add-ins if you want to change the Ribbon. The following sample is based on the XLL add-in described here.
We start with adding a command which will be executed when an item of our custom menu is clicked.
function MenuCommand: integer; stdcall;
begin
{...}
result:=1;
end;
It is added to the exports list of the DLL. Next step is to register the command in the xlAutoOpen function. An additional call with xlfRegister is put to the function. Excel4v is called with six arguments. The fifth argument doesn’t matter for commands. But the sixth argument has a default value (1 = function) and we want to pass function type 2 = command.
const
CmdP : String[20] = 'MenuCommand';
CmdT : String[20] = 'J';
CmdF : String[20] = 'SampleCommand';
function xlAutoOpen: integer; stdcall;
begin
{...}
// register menu command
Arg2.val.str:= @CmdP;
Arg3.val.str:= @CmdT; // always "J"
Arg4.val.str:= @CmdF;
Arg5.xltype:= xltypeMissing; // not required for commands
Arg6.xltype:= xltypeInt;
Arg6.val.w:= 2; // 2 = command
Excel4e(xlfRegister, nil, 6, // registers the command
[@Arg1, @Arg2, @Arg3, @Arg4, @Arg5, @Arg6]);
{...}
end;
The xlAutoRemove function should unregister the command. Now, we add three routines which are used to add and remove a custom menu. First routine is a check if the custom menu already exists.
function CheckMenu: Boolean;
var
res, mArg1, mArg2, mArg3: xloper;
begin
result:= True; // menu does not exist
mArg1.xltype:= xlTypeInt;
mArg1.val.w:= 10;
mArg2.xltype:= xlTypeStr;
mArg2.val.str:= @cMenuItems[0]; // menu name or number
mArg3.xltype:= xlTypeMissing;
if Excel4e(xlfGetBar, res, 3,
[@mArg1, @mArg2, @mArg3]) = xlretSuccess then
if res.xltype <> xlTypeErr then
result:= False; // menu exists
end;
It calls the xlfGetBar function. This function returns an error value if the menu does not exist. Parameters are the bar id of the menu bar (10 = worksheet menu), the name or number of the menu (name is more save because number may change), and the menu position. The number or name of the menu is returned if menu position is passed as xlTypeMissing.
const
cMenuItems : array[0..23] of String[20] =
('M&y Xtray Menu', '','','',
'Menu &Item 01', 'SampleCommand', '', 'shows a msgbox',
'Menu I&tem 02', 'SampleCommand', '', 'shows a msgbox',
'-', '','','',
'Menu It&em 03', 'SampleCommand', '', 'shows a msgbox',
'Menu Ite&m 04', 'SampleCommand', '', 'shows a msgbox');
procedure AddMenu;
var
mArg1, mArg2, mArg3, mArg4: xloper;
mArgX: array[0..23] of xloper;
i: Integer;
begin
if CheckMenu then begin // check if already created
mArg1.xltype:= xlTypeInt;
mArg1.val.w:= 10; // default menu bar
mArg2.xltype:= xlTypeMulti;
mArg2.val.xarray.columns:= 4; // size of
mArg2.val.xarray.rows:= 6; // array
mArg2.val.xarray.lparray:= @mArgX[0];
for i:=0 to 23 do begin
mArgX[i].xltype:= xlTypeStr;
mArgX[i].val.str:= @cMenuItems[i];
end;
Excel4e(xlfAddMenu, nil, 2,
[@mArg1, @mArg2]); // add menu
//*************************************************
mArg3.xltype:= xlTypeStr;
mArg3.val.str:= @cMenuItems[0]; // menu to add sub
mArg4.xltype:= xlTypeInt;
mArg4.val.w:= 4; // pos for sub
Excel4e(xlfAddMenu, nil, 4,
[@mArg1, @mArg2, @mArg3, @mArg4]); // add submenu
end;
end;
A custom menu is added with a call to the xlfAddMenu function. Parameters are the bar id and an array (xlTypeMulti) which describes the menu. Optional parameters are the menu and the position within the menu where array items are to be placed. The example routine creates a xlTypeMulti from a string array. Item names can include an ampersand to get a letter with underscore. Dashes as item names create a separator line. The menu is added at the end of the worksheet menu bar. A second call to xlfAddMenu is used to create a sub menu in the just created menu.
procedure DelMenu;
var
mArg1, mArg2: xloper;
begin
mArg1.xltype:= xlTypeInt;
mArg1.val.w:= 10; // default menu bar
mArg2.xltype:= xlTypeStr;
mArg2.val.str:= @cMenuItems[0]; // menu to delete
Excel4e(xlfDeleteMenu, nil, 2,
[@mArg1, @mArg2]); // delete
end;
The DelMenu routine calls xlfDeleteMenu to delete the custom menu from the menu bar. Bar id and menu name are passed in. You could store the menu position when you create the menu and pass in the menu position to xlfDeleteMenu. But, because other add-ins could change the position of your menu it’s more save to use the menu name. Last but not least, a call to AddMenu is added to xlAutoOpen and a call to DelMenu to xlAutoRemove.
You can download the full source from the download page. Feel free to post any comment.
Отлично! Большое спасибо! Вы меня спасли!
Thanks. Just as much as I still can understand without a dictionary.
Sorry! ))
Excellent simple! Thank you very much! You saved me!