Dev-Picayune

picayune: of little value or importance

Calling Clarion From Python

February 03, 2006

In my blog post Getting Jiggy with Clarion and Python, I discussed the Python oriented aspects of calling an external windows .DLL. Specifically I advocated the use of the ctypes module. This module makes the effort of dynamically linking to a .DLL nearly trivial. Continuing from my article on A Clarion Export Template, my task was to create a command-line utility for exporting some Topspeed files in Clarion to a ‘~’ delimited text file. Once I created the template and the basic program in Clarion, I had to figure out how to make it into a true command-line utility. I’m definitely not an expert in C (it’s been quite a few years since college now) so that pretty much ruled that out. And I wanted to try D but that seemed a little too much like C for something I wanted to get done in one day (although I may go back and try to redo the calling program in D at some point). So that left me with Python using ctypes.

My Python program is here:

 
import sys
from ctypes import *
 
def exportFile(tableName,outputFileName):
    wd = windll.LoadLibrary('exportfi.dll')
    cTableName = create_string_buffer(tableName,10)
    cOutputFileName = create_string_buffer(outputFileName,255)
    expcon = wd.EXPORTCONTROLLER
    expcon.restype = c_byte
    return expcon(cTableName,cOutputFileName)
 
if __name__ == '__main__':
    if len(sys.argv) != 3:
        print "usage: exportfi tablename exportfilename"
    else:
        exportFile(sys.argv[1],sys.argv[2])

This part is fairly straight forward — looking at the exportFile function:

  • My Clarion .DLL is loaded is loaded
  • New c (pointer-based) string buffers have to be created to hold the contents of the the Python variables
  • The function is identified and assigned to a local Python variable (for convenience)
  • The function’s return type is set as a c_byte
  • The return value for the function is then returned from the function call

The main Python code is the standard stuff for actually running things. It verifies that the right number of parameters were passed in and then it calls the Python function.

The trickier part is really the Clarion code. To make it more portable, I chose it to compile as seen here:

properties_screen_shot

The truly important part here is that it has to be a 32-bit application. The “Local” indicates that I want all the Clarion .DLL’s used compiled into the final .DLL output. And of course you need to select that you want to output as a .DLL rather than an .EXE.
For this particular application, I only want to export one function in the .DLL called ExportController. This function setup looks like this in the IDE:

procedure_screen_shot

You’ll notice that the “Export Procedure” check box is checked, but also (and you can’t quite see it all), I specified a special prototype.

(LONG,LONG),BYTE,PASCAL

The PASCAL part is important since it specifies the calling method and PASCAL is the standard convention for Windows .DLL’s. The parameters I just have listed as LONG’s because I’m going to need to convert the pointers into CSTRINGS after they get passed in.

The real keys to success then are found inside the function itself…

FileToConvert  CSTRING(20)
ExportName  CSTRING(255)
 
  CODE                                            ! Begin processed code
 
  lstrcpy(ADDRESS(FileToConvert),lptrTable)
  lstrcpy(ADDRESS(ExportName),lptrExport)

What we then have are useable variables in Clarion and we can proceed as normal. I should note that in order to call the Windows API lstrcpy function you need the following declaration in your GLOBAL MAP:

 
  MODULE('Windows.DLL')
     lstrcpy(LONG,LONG),LONG,PASCAL,RAW,NAME('lstrcpyA')
  END

The observant Clarion expert will notice that this is actually a bit of the lazy way out of this. I didn’t bother to import the Windows API EQUATES and I instead just defined the parameters as LONG’s for the API call (since essentially that’s what they EQUATE to).
That’s about it. You should be able to then call a Clarion .DLL from Python. And using the Clarion portion of this article, you should be able to able prep your DLL for really being called by any external language since what was done here is not specific to dealing with Python but rather just exporting a function in a standardized Windows .DLL sort of way. Enjoy!

3 comments

3 Comments so far

  1. Joshua March 12th, 2010 11:41 am

    Brandon,

    I’m trying to tackle the task of creating and exporting functions with Clarion via DLLs. I have Clarion 7.1 and many items have seemed to change from the version you used for this article! Do you have any experience creating DLLs with C7.1 and then calling them from C/python/perl/etc?

  2. ScW March 12th, 2010 11:55 am

    Actually, me (Steven aka ScW) wrote this article. Brandon and I both write for this site.

    As for your comment, I’m afraid the application I support is Clarion 5 based and won’t be moving, so I’ve not attempted a Clarion 7.1 function export.

    If I were giving advice, I’d say, try something ultra simple (no parameters) and returns a LONG. See if you can get that to work, then make a more complicated example. Good luck.

  3. Joshua March 16th, 2010 3:59 pm

    I found out what the problem with my setup was: it’s related to calling win32 DLLs from 64bit compiled code. My development machine is now running Windows 7 (64bit version). I installed the 64bit installer for Python. However, Clarion generates win32 (32 bit code).

    It ends up that calling 32bit DLLs from 64bit code is non-trivial in Windows. One trick is to build a 64bit serializing/marshaling wrapper around your 32bit code. The other trick is to avoid using 64bit code and stick to using 32bit code to call 32bit DLLs. This second approach is what I did.

    So, the issue here is not Clarion specific, but merely a problem with using mixed binary DLLs (win32/win64)

    Hope this saves someone else some grief.

Leave a reply

For spam filtering purposes, please copy the number 9804 to the field below: