Excel enables a DLL to call back into Excel. Your Delphi Add-In will need to use this feature provided with the Excel4v
and Excel12v
callback functions. We import the Excel4v
function and implement the Excel12v
function. Hence we’ve got the objects to write Delphi XLL Add-Ins.
The Excel4v
function is provided by the xlcall32.dll
. We import the function in Delphi as follows.
unit dXLCall; {...} const cxloperMax = 30; type PLPXLOPER = ^LPXLOPER; LPXLOPERarray = array[1..cxloperMax] of LPXLOPER; PLPXLOPERarray = ^LPXLOPERarray; const xlcall32 = 'xlcall32.dll'; function Excel4v(xlfn: integer; operRes: LPXLOPER; count: integer; opers: PLPXLOPERarray): integer; stdcall; external xlcall32; overload; {...}
Excel4v
is prototyped with the pascal
calling convention in the Excel SDK. This calling convention is obsolete and should be replaced with WINAPI
. But WINAPI
is just another name for stdcall
. Next we define the Excel12v
function in a similar way.
{...} const cxloper12Max = 255; type PLPXLOPER12 = ^LPXLOPER12; LPXLOPER12array = array[1..cxloper12Max] of LPXLOPER12; PLPXLOPER12array = ^LPXLOPER12array; function Excel12v(xlfn: integer; operRes: LPXLOPER12; count: integer; opers: PLPXLOPER12array): integer; stdcall; overload; {...}
Now we have done with the interface part of our dXLCall
unit. The implementation part starts with the type definition of the EXCEL12PROC
as follows.
type EXCEL12PROC = function(xlfn: integer; coper: integer; rgpxloper12: PLPXLOPER12; xloper12Res: LPXLOPER12): integer; stdcall;
The source can be translated line-by-line. We call back as follows.
{...} result:= pexcel12(xlfn, count, @opers^[1], operRes);
By the way, I fetched inline instead of using the inline
keyword. The inline
keyword is only a suggestion to the compiler and obtained a different meaning for older compiler versions.
That’s all. But we add a second unit to make Excel calls a bit easier. The Microsoft Excel SDK provides a framework library. At this point, we won’t implement a Delphi framework but define function wrappers for the Excel4v
and Excel12v
function to extend the variations in calling Excel.
unit dXLUtils; interface uses dXLCall; function Excel4e(xlfn: integer; operRes: LPXLOPER; count: integer = 0; opers: PLPXLOPERarray = nil): integer; overload; function Excel4e(xlfn: integer; var operRes: XLOPER; count: integer = 0; opers: PLPXLOPERarray = nil): integer; overload; function Excel4e(xlfn: integer; operRes: LPXLOPER; count: integer; opers: array of LPXLOPER): integer; overload; function Excel4e(xlfn: integer; var operRes: XLOPER; count: integer; opers: array of LPXLOPER): integer; overload; {...}
These routines are implemented unsophisticated but can be enhanced as shown in the framework library at a later time. We do only a call to the Excel4v
or Excel12v
as follows.
implementation function Excel4e(xlfn: integer; operRes: LPXLOPER; count: integer = 0; opers: PLPXLOPERarray = nil): integer; overload; begin result:= Excel4v(xlfn, operRes, count, opers); end; {...} function Excel12e(xlfn: integer; var operRes: XLOPER12; count: integer; opers: array of LPXLOPER12): integer; overload; begin result:= Excel12v(xlfn, @operRes, count, @opers); end; end.
These overloaded functions allow flexible calls to Excel. You can use open array constructors as parameters and you can pass the result parameter as a XLOPER
or XLOPER12
by reference without the @
-operator as in the example below.
procedure VerStackt; var a, b, c: XLOPER12; begin // pass result by ref and use default params Excel12e(xlStack, a); b.xltype:= xltypeInt; b.val.w:= xltypeStr; // pass result by val and params as dynamic array Excel12e(xlCoerce, @c, 2, [@a, @b]); b.val.w:= 3; Excel12e(xlcAlert, nil, 2, [@c, @b]); Excel12e(xlFree, nil, 1, @c); end;
Now we can start writing Excel XLL Add-Ins.
Hi Glade,
Do you write any book about these topic.
Thanks,
Duyet Le
There is only one book out there. You could try to buy a used one.
https://www.amazon.com/dp/0470027975/