[ctypes-users] codegeneration, incremental and on demand
by Thomas Heller other posts by this author
Nov 3 2006 10:01AM messages near this date
Re: [ctypes-users] html editor
|
[ctypes-users] Allocating memory for input through a structure.
I think I'm up to something very cool with the code generation.
I have written a 'dynamic_module.py' which can update another module's code
as needed on the fly. It works in this way:
First you have to call h2xml.py on the header files that describe the stuff
in the dlls, so, typically, on Windows:
python h2xml.py -D WIN32_LEAN_AND_MEAN -D NO_STRICT windows.h -c -o windows.xml
to create the windows.xml file that contains the type descriptions parsed by gccxml.
Then you write the basics of a module which will later provide access to functions, structur
es,
and constants in the dll or dlls (I'm developing this on Windows, but I see no reason
it shouldn't work on other systems also).
The module must load the dlls containing the functions you want to call,
then calls 'dynamic_module.update_from("windows.xml")'. When the module is
imported, the update_from() call gets the module from sys.modules, and replaces
it by an instance of a class that serves as a proxy for the real module.
The proxy parses the XML file for type descriptions, and has a __getattr__ implementation
that creates code on the fly when attributes are accessed from the module. The generated co
de
is executed and returned from the __getattr__ call, as well as (optionally) appended to the
source
code of the original module.
Here's a 'winapi' sample module that you have to write manually, the 'windows.xml' file
should be in the same directory:
<windows.py>
from ctypes import *
from ctypes.wintypes import * # needed on windows
_user32 = WinDLL("user32") # we need functions from the user library
from ctypeslib.dynamic_module import update_from
update_from("windows.xml")
#####
<EOF>
That's all. In an interactive session, for example, you can then access even functions, str
uctures,
constants in this way:
Python 2.4.3 (#69, Mar 29 2006, 17:35:34) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
> >> import windows
> >> windows.MessageBox(0, "foo", "bar", windows.MB_YESNOCANCEL)
6
> >> windows.c_long
<class 'ctypes.c_long'>
> >> windows.RECT
<class 'ctypes.wintypes.RECT'>
> >> windows.WNDCLASSA
<class 'windows.tagWNDCLASSA'>
> >> import pprint
> >> pprint.pprint(windows.WNDCLASSA._fields_)
[('style', <class 'ctypes.c_ulong'> ),
('lpfnWndProc', <class 'ctypes.WinFunctionType'> ),
('cbClsExtra', <class 'ctypes.c_long'> ),
('cbWndExtra', <class 'ctypes.c_long'> ),
('hInstance', <class 'ctypes.c_ulong'> ),
('hIcon', <class 'ctypes.c_ulong'> ),
('hCursor', <class 'ctypes.c_ulong'> ),
('hbrBackground', <class 'ctypes.c_ulong'> ),
('lpszMenuName', <class 'ctypes.c_char_p'> ),
('lpszClassName', <class 'ctypes.c_char_p'> )]
> >>
After you have done this, the 'windows.py' module source code looks like this:
from ctypes import *
from ctypes.wintypes import * # needed on windows
_user32 = WinDLL("user32") # we need functions from the user library
from ctypeslib.dynamic_module import update_from
update_from("windows.xml")
#####
MessageBoxW = _user32.MessageBoxW
MessageBoxW.restype = c_int
MessageBoxW.argtypes = [HWND, LPCWSTR, LPCWSTR, UINT]
MessageBox = MessageBoxW # alias
MB_YESNOCANCEL = 3 # Variable c_long
class tagWNDCLASSA(Structure):
pass
WNDCLASSA = tagWNDCLASSA
LONG_PTR = c_long
LRESULT = LONG_PTR
WNDPROC = WINFUNCTYPE(LRESULT, c_void_p, c_uint, c_uint, c_long)
HCURSOR = HICON
CHAR = c_char
tagWNDCLASSA._fields_ = [
('style', UINT),
('lpfnWndProc', WNDPROC),
('cbClsExtra', c_int),
('cbWndExtra', c_int),
('hInstance', HINSTANCE),
('hIcon', HICON),
('hCursor', HCURSOR),
('hbrBackground', HBRUSH),
('lpszMenuName', LPCSTR),
('lpszClassName', LPCSTR),
]
As one can see, structure definitions have been generated, constants like MB_YESNOCANCEL
are available, and exported functions have their restype and argtypes attributes set.
If the generated code is not exactly what you need, you can adjust it manually, or you
can add errcheck attributes to functions, for example. The changes will be seen the
next time the module is imported, and not overwritten by the code generator.
---
The next step will be to automate the XML file generation. In this case you only supply
of chunk of C code that will be converted to XML, parsed by the codegenerator, and so on.
The sample module starts like this now:
<windows-2.py>
from ctypes import *
from ctypes.wintypes import *
_user32 = WinDLL("user32")
from ctypeslib.dynamic_module import include
include("""
#define WIN32_LEAN_AND_MEAN
#define NO_STRICT
#define UNICODE
#include <windows.h>
#include <iphlpapi.h>
""")
#####
<EOF>
The 'include' function will calculate a hash of the C code string, that
will be used as a unique basename of the files that will be created in
a 'gen' or 'cache' directory somewhere.
If someone wants to look at the code, it is in
http://svn.python.org/projects/ctypes/trunk/ctypeslib/
(this was renamed from 'codegen' to 'ctypeslib' with svn mv).
Thomas
PS: windows.h parsed into XML by gccxml creates a file of several megabytes,
depending on the options used. Which is also quote slow to load, so currently
'dynamic_module' takes the parsed type descriptions, compresses them and
pickles them to disk.
The resulting file has only 20% or so of the size and loads a lot faster.
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
ctypes-users mailing list
ctypes-users@[...].net
https://lists.sourceforge.net/lists/listinfo/ctypes-users
|