1. DLL Interface

I have a need to interface with a DLL that talks to a database server. There are two versions of the DLL a 'C' version and a 'VB' version.

I have a requirement to send strings to and return strings from the DLL. The function header (C version of API)for returning the string is defined as: DB1IMPORT CHAR * DB1API DB1ValStringGet( DB1U hUser, DB1V vString );

The VB version returns a VB string and is defined as: Declare Sub DB1ValStringGet_VB Lib "db1api.dll" (ByVal hUser As Long, ByVal vString As Long, ByVal res As String, ByVal max As Integer)

What is the best way for me to get/receive strings (char arrays) from this api keeping in mind that the database and Eu program will not be on the same machine.

new topic     » topic index » view message » categorize

2. Re: DLL Interface

You could use either version of the dll. The VB version is alot simpler to implement but may not offer the full functionality of the API.

For any dll, you need to import the code you need to use into euphoria.

First, you must open the required dll and store it's handle.

constant DLL = open_dll("db1api.dll") 

then for each function you want to import, you will have to define it for euphoria

-- Declare Sub DB1ValStringGet_VB Lib "db1api.dll" (ByVal hUser As Long, ByVal vString As Long, ByVal res As String, ByVal max As Integer) 
constant C_DB1ValStringGet = define_c_proc(DLL,"DB1ValStringGet_VB",{C_LONG,C_LONG,C_POINTER,C_UINT}) 

Notice above that the defined variable C_POINTER corresponds with ByVal res as String. It's actually the memory address of the string that is passed, not the chars themselves.

C strings are terminated with a byte value of 0, so to read the string, you peek each byte starting from the string's address until you encounter a value of 0. (which is what peek_string() does in the code below)

For ease of use, you should also define a wrapper function, this is where you will handle converting char arrays to euphoria sequences and simplify the use of the API function in eu.

function DB1ValStringGet(atom hUser, atom vString) 
 atom buffer 
 integer MAX_LEN 
 sequence s 
   MAX_LEN = 255 
   buffer = allocate(MAX_LEN) 
   c_proc(C_DB1ValStringGet,{hUser,vString,buffer,MAX_LEN}) 
   s = peek_string(buffer) 
   deallocate(buffer) 
   return s 
end function 

I don't think that peek_string() is in the standard libraries, so here it is in case you need it. The optimized version is not very clear what it does, so I've provided a slow version as well.

-- unoptimized 
function slow_peek_string(atom ptr) 
 sequence s 
 integer c 
  c = peek(ptr) 
  while (c != 0) do 
    s &= c 
  end while 
  return s 
end function 
 
-- optimized 
function peek_string(atom ptr) 
 integer len 
  len = 0 
  while (peek(ptr+len) != 0) do 
   len += 1 
  end while 
  return peek({ptr,len)) 
end function 

You can read more about interfacing with C in platform.doc

HTH

new topic     » goto parent     » topic index » view message » categorize

3. Re: DLL Interface

I made a mistake in slow_peek_string() it should be:

function slow_peek_string(atom ptr) 
 sequence s 
 integer c 
  c = peek(ptr) 
  while (c != 0) do 
    s &= c 
    ptr += 1 
    c = peek(ptr) 
  end while 
 return s 
end function 
new topic     » goto parent     » topic index » view message » categorize

4. Re: DLL Interface

Excellent explanation thanks very much.

One question I have is will Peek() to directly access memory location work if the DB is running on a different machine than the euphoria program?

If not is there a possible work around.

Thanks

new topic     » goto parent     » topic index » view message » categorize

5. Re: DLL Interface

Yes it will. The DLL is actually sending a query to the remote database, and getting the answer back. The answer is in memory on your local machine, so peek will work just fine.

new topic     » goto parent     » topic index » view message » categorize

6. Re: DLL Interface

In general, it may be faster to just use the limit value, 255 in this case, as the argument to peek(). Then use find() to determine where truncate the sequence:

sequence s 
integer len 
atom ptr 
ptr = allocate( 256 ) 
-- C call using string in ptr goes here. 
s = peek( { ptr, 256 } ) 
free(ptr) 
len = find(0,s) 
if len then 
    s = s[1..len-1] 
else 
    return GET_FAIL -- too long error... 
end if 
return s 

The length of the buffer is always known by the coder and in some cases the length of the string is returned by the underlying C function. Not all C functions terminate the string. We shouldn't assume that the requested string is limited to 255 characters. It is better to fail with an error than to crash the program.

Shawn Pringle

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu