Welcome, guest | Sign In | My Account | Store | Cart
NOTE: Recipes have moved! Please visit GitHub.com/activestate/code for the current versions.

Code to call a Windows Dll """void FAR PASCAL hllapi(int FAR *, char FAR *, int FAR *, int FAR *)""" with ctypes (trivial) and calldll (a nightmare).

Python, 159 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# PROGRAM NAME : HLLAPI interface - ctypes version
# Author: Stefano Spinucci
# Written: 2002/02/16
# DESCRIPTION
# This program interface the 3270 HLLAPI library of an Italian 3270 emulator using 
# the ctypes library (home page : http://starship.python.net/crew/theller/ctypes.html
# or on sourceforge : http://sourceforge.net/projects/ctypes)
# The calling scheme for the function is :
# void FAR PASCAL hllapi(int FAR *, char FAR *, int FAR *, int FAR *);
# NOTE : 
# <from ctypes docs> Internally ctypes makes heavy use of the new type system introduced 
# in Python 2.2, so it will not work in earlier versions.

from ctypes import windll, c_int, c_string, c_char_p, byref

# ------------------------------------------------------------------------------------------------
# dll initialization
# ------------------------------------------------------------------------------------------------
#Load the dll 'Ehllapi.dll' (the file .py is in the same directory of the dll)
Ehllap32 = windll.ehllap32
#Load the function 'hllapi' from the dll
hllapi = Ehllap32.hllapi

# ------------------------------------------------------------------------------------------------
# variables setting and function calling
# ------------------------------------------------------------------------------------------------
#Set the variables
h_func = c_int(1)
h_text = c_string('A')
#alternatively to "h_text = c_string('A')" you can use "h_text = c_char_p('A')"
h_len = c_int(1)
h_ret = c_int(999)

#Function calling
hllapi(byref(h_func), h_text, byref(h_len), byref(h_ret))

#Print the value returned
print h_func.value
print h_text.value
print h_len.value
print h_ret.value






# PROGRAM NAME : HLLAPI interface - calldll version
# Author: Stefano Spinucci
# Written: 2002/02/16
# DESCRIPTION
# This program interface the 3270 HLLAPI library of an Italian 3270 emulator using 
# the calldll library (from Sam Rushing http://www.nightmare.com/software.html)
# I've found very useful also edll.py from http://pages.ccapcable.com/lac/undergroundPython.html
# The calling scheme for the function is :
# void FAR PASCAL hllapi(int FAR *, char FAR *, int FAR *, int FAR *);

# ------------------------------------------------------------------------------------------------
# Function defining : 
# - myPrintLong : given a membuf with a long inside, print the long
# - myPrintString : given a membuf with a string inside, print the string
# - mySetLong : given a membuf with len = 4, set his value with the long passed
# - mySetString : given a membuf, set his value with the string passed (adding the character \0)
# ------------------------------------------------------------------------------------------------

def myPrintLong(vVar):
	#Print the long (first way)
	a= struct.unpack('I', vVar.read())[0]
	print a

	#Print the long (second way)
	print calldll.read_long(vVar.address())

def myPrintString(vVar):
	#Print the string (first way)
	a = vVar.read()
	print a[:len(a)-1]
	print len(a)

	#Print the string (second way)
	a = calldll.read_string(vVar.address())
	print a
	print len(a)

def mySetLong(vMemBuf, vValueToSet):
	string_packed = struct.pack("L",vValueToSet) # packed as unsigned long
	vMemBuf.write(string_packed)

def mySetString(vMemBuf, vValueToSet):
	data_len = len(vValueToSet) 
	pack_format = str(data_len+1)+"s" # add one for \0 at the end. 
	string_packed = struct.pack(pack_format, vValueToSet) # pack() will add \0 for us
	vMemBuf.write(string_packed)

# ------------------------------------------------------------------------------------------------
# Import the required library
# ------------------------------------------------------------------------------------------------

#Import the calldll module
import calldll
#Import the struct module (a standard python module)
import struct

# ------------------------------------------------------------------------------------------------
# Get the handle of the dll and the address of the function
# ------------------------------------------------------------------------------------------------

#Get the handle of the Dll
handle = calldll.load_library ('C:\Tee3270\Ehllap32')

#Get the address of the function
address = calldll.get_proc_address (handle, 'HLLAPI')

# ------------------------------------------------------------------------------------------------
# Initialization
# ------------------------------------------------------------------------------------------------
# vFunction, vTextLen and vResult are defined as a membuf with lenght = 4, because 4 is the lenght 
# of an unsigned long packed with struct.pack("L", NumberToPack)
vFunction = calldll.membuf(4)
vTextLen = calldll.membuf(4)
vResult = calldll.membuf(4)
# vFunction is defined as a membuf with lenght = 1921 because the dll needs a buffer of 
# 1920 char + 1 for \0 at the end
# You can here define a membuf of the lenght you need + 1 for the last \0 character
vText = calldll.membuf(1921)

# ------------------------------------------------------------------------------------------------
# Function calling
# ------------------------------------------------------------------------------------------------

# Vars setting
#1
mySetLong(vFunction, 1)
#2
string_value_to_write = 'A'
mySetString(vText, string_value_to_write)
#3
mySetLong(vTextLen, len(string_value_to_write))
#4
mySetLong(vResult, 1)

#Call the function
calldll.call_foreign_function (
			address,
			'llll',
			'l',
			(vFunction.address(), vText.address(), vTextLen.address(), vResult.address())
			)


myPrintLong(vResult)
myPrintString(vText)

# ------------------------------------------------------------------------------------------------
# Dll unloading
# ------------------------------------------------------------------------------------------------

#Unload the dll
calldll.free_library (handle)

Some days ago I had to call a Windows dll (who needs int and char pointers) with calldll, and I failed. Then I discovered ctypes (http://starship.python.net/crew/theller/ctypes.html) and it was trivial. However I'd like to use also calldll (http://www.nightmare.com/software.html)... I won, and the code I posted 'll show you the two solutions. I posted the calldll solution because there is so few documentation, and I think my code can help someone ;-) The ctypes code is posted only to show you this beautiful library I hope become famous.