No announcement yet.

Calling a PowerBASIC DLL from C

  • Filter
  • Time
  • Show
Clear All
new posts

  • Calling a PowerBASIC DLL from C

    I am attempting to call a PB/DLL created DLL from C. I have no
    problems with Asciiz strings or numerics when the function parameter uses BYVAL.

    The following is the "test" function I am using. Some functions in the DLL use PB
    dynamic (variable length) strings and numerics passed by reference. The DLL is not
    mine so I can't change its functions.
    When i run the C program the first parameter gets logged to the file just fine, but
    the 2nd and 3rd parameters do not make it. A protection fault is raised.

    Here's what currently gets logged by the PB Dll:
    lDBN: 1 lDBName: ! lPrompt:
    lDBN: 1 lDBName: ! lPrompt:
    lDBN: 1 lDBName: ! lPrompt:

    '[b]RP_TEST.DLL code[/b]
    Function RP_TestDLL Alias "RP_TestDLL"(ByVal lDBNumber As Long, _
                        ByVal lDBname As String, _
                        lPrompt As Long) Export As Long
      Open "D:\LCC\Sqltest\RP_TestDLL.Log" For Append As #1
      Print #1, $CrLf;"lDBN:"; lDBNumber, "  lDBName: "; lDBName;"!","  lPrompt:";lPrompt
      Close 1
      Function = 199
    End Function
    The C code I am using to call the function in the PB Dll is:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <win.h>
    typedef int __stdcall RP_TestDLL( int lDBNumber,
                                      CHAR* lDBname,
                                      int &Prompt );
    int main(int argc,char *argv[])
      DWORD rc=0;
      CHAR dbn[128];
      RP_TestDLL* pRP_TestDLL;
      HMODULE hRPDll;
      pRP_TestDLL = (RP_TestDLL* ) GetProcAddress(hRPDll,"RP_TestDLL");
      hRPDll = LoadLibrary("RP_Test.dll");
      printf("Loaded DLL: %d\r\n",hRPDll );
      if (hRPDll == NULL) printf( "hRPDll = Null\r\n");
        sprintf( dbn, "DRIVER=SQL Server;server=DevTestServer;database=DB1;uid=dbuser;pwd=pwrd\0"); 
        printf ("Before Calling RP_TestDLL - pRP_TestDLL: %d\r\n", pRP_TestDLL );
        rc = pRP_TestDLL(1,
                         123 );
      return 0;
    Any help very much appreciated.

    [This message has been edited by Ron Pierce (edited August 19, 2000).]

  • #2
    hi ron

    the reason you are getting gpfs is because c does not natively
    use bstrs (pb dynamic strings). since you can't change the dll
    to use asciiz you'll need to handle bstrs from c as in the
    following example. there was a long discussion on that subject

    here's some example code that shows how to handle bstrs from
    c and pass them to pbdll

    // c code
    #include <windows.h>
    #include <stdio.h>
    #include <oleauto.h>
    typedef int __stdcall lpfncalldll( int dbnumber, bstr dbname, int &prompt  );
    int __cdecl main( int argc, char *argv[], char *envp[] ) 
    	hmodule hlib;
    	lpfncalldll* lpcalldll;
    	bstr bstring;
    	char *chdsn;
    	int prompt;
    	int lreturn;
    	hlib = loadlibrary( "mydll.dll" );
    	if ( hlib == null )
    		printf( "could not load mydll.dll" );
    		return false;
    	lpcalldll = (lpfncalldll*)getprocaddress( hlib, "myfunction" );
    	if ( lpcalldll == null )
    		freelibrary( hlib );
    		return false;
    	chdsn = "driver=sql server;server=devtestserver;database=db1;uid=dbuser;pwd=pwrd";
    	/* use ole strings */
    	bstring = sysallocstringbytelen( chdsn, strlen(chdsn) ); 
    	if ( bstring==null ) 
    		printf( "could not allocate string" );
    		return false;
    	prompt = 123;
    	lreturn = lpcalldll( 1, bstring, prompt );
    	if ( lreturn != 0 )
    		printf( "function returned %d", lreturn );
    	/* ole string must be freed afer use */
    	sysfreestring( bstring );
    	freelibrary( hlib );
    	return true;
    'basic code
    #compile dll
    #include ""
    function myfunction alias "myfunction" ( byval ldbnumber as long, byval sdbname as string, byref lprompt as long ) export as long
      open "c:\temp\rp_testdll.log" for append as #1
      print #1, $crlf;"ldbn:"; ldbnumber, "  dbname: "; sdbname;"!","  lprompt:";lprompt
      close 1
      function = 199
    end function
    function libmain(byval hinstance   as long, _
                     byval fwdreason   as long, _
                     byval lpvreserved as long) export as long
      select case fwdreason
        case %dll_process_attach
           libmain = 1   'success!
          exit function
        case %dll_process_detach
           libmain = 1   'success!
          exit function
        case %dll_thread_attach
           libmain = 1   'success!
           exit function
        case %dll_thread_detach
           libmain = 1   'success!
          exit function
      end select
    end function
    note that if the dll declare byref sdbname as string instead of
    byval sdbname as string you'd need to declare the function
    prototype in c as:
    typedef int __stdcall lpfncalldll( int dbnumber, bstr &dbname, int &prompt );

    [this message has been edited by florent heyworth (edited august 19, 2000).]


    • #3
      Thanks for the superb help Florent. The BSTR and other oleaut functions were the cure!