# an interactive tutorial for bgen # # Thomas Heller, Aug 2001 # # Read through the text in a Python IDE of your choice, uncomment # the lines between the #------------ tags one after the other, run this file, # watch the output, comment them out again, and continue reading and exploring. from bgen import * """ Lets try to put bgen to work. Sample project: Generate a module wrapping some parts of the win32 API concerned with Device Contexts (HDC). Creating a Device Context There are several ways to create a device context. Unfortunately the device context must be freed after use with functions depending on how it was created, so for now we only use HDC GetDC(HWND hwnd) and BOOL ReleaseDC(HWND hwnd, HDC hdc). Probably it is best to create a new Python object wrapping the Device Context, we use bgen.ObjectDefinition for that. According to the doc-string the constructor must be called with the object's official name, a prefix to use for the object's functions and data, and the C type actually contained in the object: """ hdcobj = ObjectDefinition("HDCObj", "HDC", "HDC") #------------ #hdcobj.generate(); raise SystemExit #------------ """ Running test() will show us the code implementing the object - which I will not repeat here. To actually create an extensionmodule we need to create a bgenModule and add the hdbobj definition to it - since we use the win32 api we have to include windows.h: """ hdcmod = Module("hdc", includestuff="#include ") hdcmod.addobject(hdcobj) #------------ #hdcmod.generate(); raise SystemExit #------------ """ To actually build the extension module, we must set an output filename, and finally we can use distutils to build the stuff. Note: Since I'm running this on Windows, and MSVC failes on the line PyObject_HEAD_INIT(&PyType_Type) with 'error C2099: initializer is not a constant' when compiling C-code, we create a C++ source file. """ def build(mod): SetOutputFileName("hdc.cpp") mod.generate() SetOutputFileName() from distutils.core import setup, Extension ext = Extension("hdc", sources=["hdc.cpp"], libraries=["user32"]) setup(ext_modules=[ext], script_name="dummy", script_args=["-q", "install", "--install-platlib=."]) return __import__("hdc") #------------ #hdc = build(hdcmod); hdc; print dir(hdc); raise SystemExit #------------ """ If all went well, executing the above line should have printed ['Error', 'HDCObjType', '__doc__', '__file__', '__name__']. To do something with a HDC, we need one - see the GetDC function above. The easiest way is to retrieve one from a Window already existing - the desktop window for example. In win32 window handles are simply integers representing windows of course, but for simplicity we don't create extension types for them - we use them as integers. So we need a function in our extension wrapping the API HWND GetDesktopWindow(void) - nothing easier than that with bgen. bgen exports an 'int' type - not to be confused with the python function of the same name. Running the line below will show the code for this function: """ GetDesktopWindow = FunctionGenerator(int, "GetDesktopWindow") #------------ #GetDesktopWindow.generate(); raise SystemExit #------------ """ Adding this function to our module and rebuilding is easy: """ hdcmod.add(GetDesktopWindow) #------------ #build(hdcmod) #------------ """ Oops, it didn't work. The compiler complaines hdc.cpp(93) : error C2440: '=' : cannot convert from 'struct HWND__ *' to 'int' What to do? We need to define another type for HWND - and maybe we should take a fresh start with our module. """ del hdcmod hdcmod = Module("hdc", includestuff="#include ") hdcmod.addobject(hdcobj) """ We create a simple bgen Typeby specifying the C type name, and the Python conversion code - used in Py_BuildValue and PyArg_ParseTuple. """ HWND = Type("HWND", "i") GetDesktopWindow = FunctionGenerator(HWND, "GetDesktopWindow") hdcmod.add(GetDesktopWindow) #------------ #hdc = build(hdcmod); print "HWND", hdc.GetDesktopWindow(); raise SystemExit; import hdc #------------ """ Yup - now it worked. On my system, it printed 'HWND 65548'. Fine, now lets take our HDC object to use - we want to retrieve a device context for the desktop window. First we have to define the HDC type itself - but this is not a simple type like HWND (XXX Shouldn't it be better to make this available via a method from the ObjectDefinition?) """ HDC = OpaqueType("HDC", "HDC") """ Taking the GetDC function from above, we can now write... """ GetDC = FunctionGenerator(HDC, # return value "GetDC", # function name (HWND, "hwnd", InMode)) #------------ #GetDC.generate() #------------ """ ... and we have a perfectly valid function wrapping the GetDC API function. Now we can build, and retrieve the device context for the desktop window: """ hdcmod.add(GetDC) #------------ #hdc = build(hdcmod); print hdc.GetDC(hdc.GetDesktopWindow()); raise SystemExit #------------ """ Prints on my system. Hey - we have a system resource leak: The device context is never freed again with ReleaseDC(). """