Historical Complete Guide to Using DLLs in OpenEuphoria, Revision 1

Complete Guide to Using DLLs in OpenEuphoira

Table of Contents

TODO: ADD TOC The table of contents plugin does not seem to be working.

Why

Over the years many programs have been written that take advantage of previously written code stored in dynamically linked libraries. On Windows these libraries have a .dll extension and on Linux/Unix they often end with a .so extension. These libraries can provide functionality for your program that would otherwise take years to achieve. These features include networking, graphics, sound, GUI, and much more.

What

This is a non-trivial topic and will need to be spread out over several sections. In this section we'll build a small DLL that will start our adventure into using libraries in our Euphoria programs. In the next few sections we'll explore some real world examples.

Prerequisites

This guide has prerequisites. I believe the lists below to be complete. If any other prerequisites pop up during the evolution of this guide I'll be sure to update this section.

Knowledge

At this point it's unavoidable. Some knowledge of C is required. While expert knowledge is not required you should be familiar with C header files and C data types. Additionally, I'll assume that you understand pointers and structs as many, perhaps all, DLLs that you'll want to use will take advantage of at least one of these features, probably both.

I like using Makefiles for tasks. If you copy my examples make sure you know that line indents in a Makefile are [TAB]s not [SPACE]s

Reading

  • Dynamic Linking to external code - Most of this page describes C type constants. There are only 7 functions in std/dll.e and you'll need 6 of them in this first guide.
  • Machine Level Access - For this guide you'll primarily use the poke and peek functions from ste/machine.e. There are several of these and you should know what each does.
  • UsingDLLs - This is a light and breezy introduction to this topic.

Tools

It is possible to use other tool chains. In fact people do it all the time. But this is the tool chain I'm using. If you prefer a different tool chain you may need to adapt the some parts of this guide to use your tools.

Additionally, I'm using Linux. I'll try hard to keep Linux-isms to a minimum as the entire concept is a near perfect match between Linux and other platforms.

How

The first step of this process is really about identifying the right library for the job. As you search for the right solution it's important to note that C is not CPP. It is possible to use CPP DLLs in OpenEuphoria but that first involves creating a C wrapper. So, if you want to skip wrapping CPP code into C wrappers, try to find the functionality you're looking for written in C in the first place.

So, What is a wrapper? "A wrapper function is a function in a computer program whose main purpose is to call a second function with little or no additional computation". In our case we are creating a DLL wrapper which I'll define as a collection of wrapper functions used to make working with DLLs practical and in some cases, possible. The goal is to translate the C header files to OpenEuphoria constructs and then use the wrapper in our programs.

Example

Full Source

guitar.h
typedef struct 
{ 
  int string_count; 
  char* brand; 
} Guitar; 
 
/* Initialize an new guitar struct  
 *  
 * returns a pointer to the new guitar 
 * */ 
Guitar * guitar_new(); 
 
/* Free up the guitar and release it from memory 
 * This function will also free up the guitar.brand memory 
 * */ 
void guitar_destroy(Guitar * guitar); 
 
/*Sets the string_count value for the guitar 
 *  
 * Guitar * guitar The struct that needs a new string count value 
 * Int count the new number of string for the guitar 
 * */ 
void guitar_set_string_count(Guitar * guitar, int count); 
 
/*Gets the string_count value for the guitar 
 *  
 * Guitar * guitar The struct holds the string count value we want 
 *  
 * returns an integer value for the number of strings. 
 * */ 
int guitar_get_string_count(Guitar * guitar); 
 
/*Sets the brand value for the guitar.   
 * Frees the current brand char * 
 * Copies the const * brand into a new char * 
 * sets the guitar brand to this new copied value.  
 *  
 * Guitar * guitar The struct that needs a new brand value 
 * */ 
void guitar_set_brand(Guitar * guitar, const char * brand); 
 
/*Gets the brand pointer for the guitar 
 *  
 * Guitar * guitar The struct holds the brand value we want 
 *  
 * returns an char * for the guitar brand. 
 * */ 
const char * guitar_get_brand(Guitar * guitar); 

guitar.c
#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include "guitar.h" 
 
void guitar_set_string_count(Guitar * guitar, int count) 
{ 
  guitar->string_count = count; 
} 
 
int guitar_get_string_count(Guitar * guitar) 
{ 
  return guitar->string_count; 
} 
 
void guitar_set_brand(Guitar * guitar, const char * brand) 
{ 
  if (guitar->brand != NULL) 
  { 
      free(guitar->brand); 
  } 
  char * new_brand = (char*)malloc(strlen(brand)+1); 
  strncpy(new_brand, brand, strlen(brand)); 
  new_brand[strlen(brand)] = '\0'; 
  guitar->brand = new_brand; 
} 
 
const char * guitar_get_brand(Guitar * guitar) 
{ 
  return guitar->brand; 
} 
 
void guitar_destroy(Guitar * guitar) 
{ 
  if (guitar->brand != NULL) 
  { 
      free(guitar->brand); 
      guitar->brand=NULL; 
  } 
   
  free(guitar); 
} 
 
Guitar * guitar_new() 
{ 
  Guitar * guitar; 
  guitar = (Guitar*)malloc(sizeof(Guitar)); 
  memset(guitar, '\0', sizeof(Guitar)); 
  return guitar; 
} 

Makefile
all: 
	gcc -shared -fPIC -o guitar.so guitar.c  

guitar.ex

#!/usr/bin/env eui 
include std/dll.e 
include std/machine.e 
 
-- Globals 
atom  dllid_guitar_dll,  
      rid_guitar_new,  
      rid_guitar_destroy,  
      rid_guitar_set_brand, 
      rid_guitar_get_brand, 
      rid_guitar_set_string_count, 
      rid_guitar_get_string_count 
 
-- Wrapper functions.  So using the dll seems more Euphoria like. 
function guitar_new() 
  return c_func(rid_guitar_new, {}) 
end function 
 
procedure guitar_destroy(atom guitar) 
  c_proc(rid_guitar_destroy, {guitar}) 
end procedure 
 
procedure guitar_set_brand(atom guitar, sequence brand) 
  atom brand_ptr = allocate_string(brand) 
  c_proc(rid_guitar_set_brand, {guitar, brand_ptr} ) 
end procedure 
 
function guitar_get_brand(atom guitar) 
  atom brand_ptr = c_func(rid_guitar_get_brand, {guitar}) 
  sequence brand = {} 
  brand = peek_string(brand_ptr) 
  return brand   
end function 
 
procedure guitar_set_string_count(atom guitar, integer cnt) 
  c_proc(rid_guitar_set_string_count, {guitar, cnt} ) 
end procedure 
 
function guitar_get_string_count(atom guitar) 
  integer cnt = c_func(rid_guitar_get_string_count, {guitar}) 
  return cnt 
end function 
 
-- Main -- 
-- Make sure we can open the dll before we go any further -- 
dllid_guitar_dll = open_dll({"./guitar.dll", "./guitar.so"}) 
if dllid_guitar_dll = 0 then 
  puts(2, "Could not find or open dynamic lib guitar") 
  abort(1) 
end if 
 
-- We need an identifier that represents our c routine.  This is accomplished by 
-- mapping the dll function prototype (or signature if you prefer) to something  
-- Euphoira will know how to handle. 
rid_guitar_new = define_c_func(dllid_guitar_dll, "guitar_new", {}, C_POINTER) 
rid_guitar_destroy = define_c_proc(dllid_guitar_dll, "guitar_destroy", {C_POINTER}) 
rid_guitar_set_brand = define_c_proc(dllid_guitar_dll, "guitar_set_brand", {C_POINTER, C_POINTER}) 
rid_guitar_get_brand = define_c_func(dllid_guitar_dll, "guitar_get_brand", {C_POINTER}, C_POINTER) 
rid_guitar_set_string_count = define_c_proc(dllid_guitar_dll, "guitar_set_string_count", {C_POINTER, C_INT}) 
rid_guitar_get_string_count = define_c_func(dllid_guitar_dll, "guitar_get_string_count", {C_POINTER}, C_INT) 
 
atom guitar = guitar_new() 
guitar_set_brand(guitar, "fender") 
guitar_set_string_count(guitar, 6) 
printf(1, "Your guitar is a %d string %s\n", {guitar_get_string_count(guitar), guitar_get_brand(guitar)}) 
guitar_destroy(guitar) 

Search



Quick Links

User menu

Not signed in.

Misc Menu