Author Topic: Dynamic API calls  (Read 9691 times)

0 Members and 1 Guest are viewing this topic.

Offline Gérôme Guillemin

  • Newbie
  • *
  • Posts: 12
  • User-Rate: +0/-6
Dynamic API calls
« 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) :

Code: [Select]
//--------------------------------------------------------------------------------
//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 !
« Last Edit: March 22, 2009, 11:22:47 PM by Gérôme Guillemin »

Offline Theo Gottwald

  • Administrator
  • Hero Member
  • *****
  • Posts: 919
  • User-Rate: +30/-4
    • it-berater
Re: Dynamic API calls
« Reply #1 on: March 04, 2009, 08:49:40 AM »
Looks interesting, does somebody have this as PB-Code?

Offline Patrice Terrier

  • ROMs
  • Hero Member
  • *****
  • Posts: 936
  • User-Rate: +62/-1
    • www.zapsolution.com
Re: Dynamic API calls
« Reply #2 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

Code: [Select]
    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.
« Last Edit: March 04, 2009, 10:17:42 AM by Patrice Terrier »
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Offline Eros Olmi

  • Full Member
  • ***
  • Posts: 243
  • User-Rate: +18/-7
    • thinBasic
Re: Dynamic API calls
« Reply #3 on: March 04, 2009, 09:02:23 PM »
thinBasic Script Interpreter - www.thinbasic.com | www.thinbasic.com/community
Win7Pro 64bit - 8GB Ram - Intel i7 M620 2.67GHz - NVIDIA Quadro FX1800M 1GB