Powerbasic Museum 2020-B

IT-Consultant: Frederick J. Harris => Fred's API (Application Programming Interface) Tutorials => Topic started by: Gérôme Guillemin on February 04, 2009, 11:32:54 AM

Title: Dynamic API calls
Post by: Gérôme Guillemin on February 04, 2009, 11:32:54 AM
Hello,

For those that are interested in Dynamic API call, I wrote years ago a simple API Call layer that was used into AutoHotkey scripting language and co.
Here's the C code MSVC++ and LCC WIn32 compatible (may be adapted for GCC) :


//--------------------------------------------------------------------------------
//Author : Gerome GUILLEMIN
//Dynamic API :: the ultimate code !   
//--------------------------------------------------------------------------------
//!!!!!!!!!!!! POWER !!!!!!!!!!!!
//If you appreciate this sample code, please register to FBSL 
//Enjoy and take care 
//--------------------------------------------------------------------------------

//  Examples :

/*
   CallDllFx("Sleep","kernel32",1, 1000);
   CallDllFx("SleepEx","kernel32",2, 2000, 1);
   CallDllFx("WritePrivateProfileString","kernel32", 4, "Section1", "SecondKey", "By golly, it works.", "c:\\appname.ini");
*/

// C implementation:

int WINAPI CallDllFx (char *FuncName, char *DllName, int nArgs, ...)
{
HINSTANCE  hInst = 0;
FARPROC lpAddr    = 0;
int arg    = 0;
int result = 0;
char buff[128] = {'\0'};
va_list ap;
int argtable[128]; //[nArgs]; // in LCC WIN32 because of the Dynamic Support !
   
   memset( &argtable, 0, sizeof(argtable) );

   hInst=GetModuleHandle(DllName);
   if(hInst==NULL) {
      hInst=LoadLibrary(DllName);
   }
   else {
      //DBS( "(0)Library '%s' already loaded !", DllName );
   }
   lpAddr=(FARPROC)GetProcAddress(hInst,FuncName);
   if(lpAddr==NULL) {
      sprintf(buff,"%s%s",FuncName,"A");
      lpAddr=(FARPROC)GetProcAddress(hInst,buff);
   }
   if(lpAddr==NULL) {
      sprintf(buff,"%s%s","_",FuncName);
      lpAddr=(FARPROC)GetProcAddress(hInst,buff);
   }
   if (lpAddr) {
      va_start(ap,nArgs);
      for (register int i=0; i<nArgs;i++) {
         arg = va_arg(ap,int);
         argtable[i] = arg;
      }
      for (register int ii=nArgs-1;ii >=0; ii--) {
         arg = argtable[ii];
      }
      va_end( ap );
      __try {
         result = lpAddr();
      } __except ( EXCEPTION_EXECUTE_HANDLER ) {
         if (hInst) FreeLibrary(hInst);
         return -1;
      }

   }

   if(hInst) FreeLibrary(hInst);

return result;
}


Enjoy !
Title: Re: Dynamic API calls
Post by: Theo Gottwald on March 04, 2009, 08:49:40 AM
Looks interesting, does somebody have this as PB-Code?
Title: Re: Dynamic API calls
Post by: Patrice Terrier on March 04, 2009, 10:06:19 AM
Theo,

This is the same technic being used in WinDev (PC-Soft) to call a DLL from their WL p-code.

It is not that hard to translate to PB ;)

Here is a small example, i wrote many years ago to encapsulate the first version of BASS.DLL


    hBassDll??? = LoadLibrary("BASS.DLL")
    IF hBassDll??? THEN
       hBassWmaDll??? = LoadLibrary("BASSWMA.DLL")
       pBassPtr = GetProcAddress(hBassDll???, "BASS_GetVersion")
       IF pBassPtr THEN
          CALL DWORD pBassPtr USING BASS_GetVersion TO Ret???
          Version$ = TRIM$(STR$(LOWRD(Ret???))) + "." + TRIM$(STR$(HIWRD(Ret???)))
       END IF
       BassVer& = VAL(Version$) * 10
       IF BassVer& >= 18 THEN ' Basscd.dll requires at leats BASDLL version 1.8
          hBassEncodeDll??? = LoadLibrary("BASSENC.DLL")
          hBassCdDll??? = LoadLibrary("BASSCD.DLL")
          IF BassVer& >= 20 THEN ' Basscd.dll requires at leats BASDLL version 1.8
             hBassVisDll??? = LoadLibrary("BASS_VIS.DLL")
          END IF
       END IF
    END IF
 

Added:
For the optional parameters, there is an ASM source code somewhere in POFF showing how to pass multiple parameters, that was done to work arround the PB6 or PB7 limitation of passing more than 16 parameters.

And for the current version, see the use of the "optional" keyword.
Quote
Using classic optional parameters

When declaring a CDECL SUB or FUNCTION, you can specify trailing parameters as optional, using a set of brackets [..]:

DECLARE SUB KerPlunk CDECL (x%, y% [, z%])

Note that the comma separating the y% parameter from the optional z% parameter is inside the brackets.  The following calling sequences would then be valid:

CALL KerPlunk (x%, y%)

CALL KerPlunk (x%, y%, z%)

Optional parameters must be the last parameters designated in the list.
Title: Re: Dynamic API calls
Post by: Eros Olmi on March 04, 2009, 09:02:23 PM
Quote from: Theo Gottwald on March 04, 2009, 08:49:40 AM
Looks interesting, does somebody have this as PB-Code?

Written some ages ago ...
http://www.powerbasic.com/support/pbforums/showthread.php?t=24175&highlight=calldll