The DLCALL function calls any Windows dynamic link library (DLL) and loads it into memory for use with R:BASE.
Syntax for External DLL:
(DLCALL('libraryname.ext', 'FunctionOrProcedureName', [arg],[arg],[.....]))
Syntax for Windows API:
(DLCALL('libraryname', 'FunctionOrProcedureName', [arg],[arg],[.....]))
External DLLs must have the file name listed with the extension, such as 'MyLibrary.dll'.
Windows APIs require only the name of the Library, without the extension, such as: 'Kernel32' or 'User32'.
The DLLs must be created as Standard Windows 32-bit DLLs. Any number of functions or procedures can be used in a single DLL. Functions or procedures to be used with DLCALL must be exported in the DLL. No special code is necessary in the DLL for it to be used by R:BASE.S
DLL Location:
DLLs can be located in the legal Windows search path, and if elsewhere, then specify the full path name in the DLLoad function.
Search Path Used by Windows to Locate a DLL
With both implicit and explicit linking, Windows first searches for "known DLLs", such as Kernel32.dll and User32.dll. Windows then searches for the DLLs in the following sequence:
1.the directory where the executable module for the current process is located
2.the current directory
3.the Windows system directory. The GetSystemDirectory function retrieves the path of this directory.
4.the Windows directory. The GetWindowsDirectory function retrieves the path of this directory.
5.the directories listed in the PATH environment variable
When or If DLLOAD is Used:
DLLOAD may be called "anytime" during the session to load the library into memory or as a subsequent call to determine if the library is Loaded.
In any event, DLLOAD is called internally when the library is first referenced by DLCALL, and then the library remains in memory until either the R:BASE session is closed or DLFREE is called.
Data Type Rules:
Data types in the functions must be of the same storage size as the corresponding R:BASE data types.
Example: 32-bit Win32 Integer = 4 bytes of storage vs 32-bit R:BASE Integer = 4 bytes of storage
Declaration Logic:
Calls to a function or procedure from any dynamic link library must be declared at least once in the session in which they will be referenced.
Two calling conventions are supported, using the STDCALL and CDECL keyword in the declaration.
Example of a DLL created in Delphi exporting three functions:
// Begin Dll Code
library DemoLib;
uses
SysUtils, Classes;
{$R *.res}
function MultInt (NumIN : Integer) : Integer; stdcall;
begin
Result := (NumIN * 2);
end;
function MultDbl (NumDbl : Double) : Double; stdcall;
begin
Result := (NumDbl * 2);
end;
procedure LCaseByREF(DataIN : PChar); stdcall;
begin
ansiStrLower(DataIN);
end;
function LCaseByVAL (DataIN : PChar) : PChar; Stdcall;
begin
Result := ansiStrLower(DataIN);
end;
Exports MultInt, LCaseByREF, LCaseByVAL;
begin
end.
// End Dll Code
Example Usage From Within R:BASE:
-- BEGIN Demo.rmd
-- Declare the functions to be used from the DLL
STDCALL function 'MultInt' ( Integer ) : Integer
STDCALL VOID 'LCaseByREF' (ptr TEXT (30))
STDCALL function 'LCaseByVAL (ptr TEXT (60)) : TEXT (60)
--Set somme variables for use
Set VAR vTEXT TEXT = 'RBASE TECHNOLOGIES'
SET VAR vINT INTEGER = 128
SET VAR v1 INTEGER = 0
-- OPTIONALLY CALL DLLOAD
SET VAR v1 = (DLLOAD('DemoLib.dll'))
IF v1 = 0 THEN
PAUSE 2 USING 'DemoLib.dll NOT LOADED.. EXITING'
RETURN
ENDIF
SET VAR V1 = (dlcall('demolib.dll', 'changecase', vtext))
{ The Value for v1 will be null because ChangeCase is a procedure and doesn't
RETURN A RESULT, but the value of vTEXT which is passed as a POINTER has been
changed to 'rbase technologies'}
SET VAR v1 = (DLCALL('demolib.dll', 'MultInt', vINT))
--The value for v1 will be 256 the value returned from the function.
-- running the following against RRBYW20
SELECT (DLCALL('demolib.dll','lcasebyval', Company))=60 FROM +
Customer WHERE LIMIT = 2
{Yields the following output:
(DLCALL('demolib.dll','lcasebyval', Company)
------------------------------------------------------------
computer warehouse - ii
microtech university - i
}
SELECT ((ICAP2((DLCALL('demolib.dll','lcasebyval', Company))))) = 60 +
FROM Customer WHERE LIMIT = 2
{Yields the following otput:
((ICAP (DLCALL('demolib.dll','lcasebyval',
------------------------------------------------------------
Computer Warehouse - Ii
Microtech University - I
}
-- Optionally CALL DLFREE
SET VAR v1 = (DLFREE('DemoLib.dll'))
-- END Demo.rmd
Example of a DLL created in C++ Exporting three functions:
// BEGIN C++ DLL
// loaddll.cpp : Defines the entry point for the DLL application.
//
#include <windows.h>
#include <stdio.h>
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
#ifdef __cplusplus // If used by C++ code,
extern "C" { // we need to export the C interface
#endif
__declspec(dllexport) int cfunc1(int i){
return i;
}
__declspec(dllexport) double cfunc2(double *inp){
double rtn = *inp;
rtn++;
return rtn;
}
__declspec(dllexport) char * cfunc3(char *inp){
strcat(inp," + ");
return inp;
}
#ifdef __cplusplus
}
#endif
// END C++ DLL
See Also:
Special thanks to:
Mike Byerley (Fort Wayne, Indiana) for his contribution to the introduction, implementation and testing of the DLCALL function in R:BASE.