DLL in Python
Alex Martelli
aleaxit at yahoo.com
Tue Oct 24 03:41:47 EDT 2000
"Mike Müller" <mmueller at dgfz.de> wrote in message
news:8t35kk$1j8 at micky.ibh-dd.de...
[snip]
> Thanks for yur hint. But don't konw where to put the
"__declspec(dllexport)"
Right before the returntype of the function you want to export, e.g:
__declspec(dllexport)
int test_int4(int x, int y)
{
PyErr_Clear();
PyObject* result = PyObject_CallMethod(
module_object, "test_int4", "ii", x, y);
if(!result) {
/* disaster -- make it known somehow, e.g: */
fprintf(stderr, "Error calling test_int4(%d,%d)\n", x, y);
if(PyErr_Occurred()) {
PyErr_Print();
}
return 0;
} else {
PyObject* pintresult = PyNumber_Int(result);
Py_DECREF(result);
if(!pintresult) {
/* other disaster -- make it known somehow, e.g: */
fprintf(stderr, "test_int4(%d,%d) returned non-int\n", x, y);
if(PyErr_Occurred()) {
PyErr_Print();
}
return 0;
} else {
int intresult = PyInt_AS_LONG(pintresult);
Py_DECREF(pintresult);
return intresult;
}
}
}
freeze doesn't build such C function wrappers for you -- they'd be no
use except to 'expose' the Python functions as C ones, and also there
is no way to build them except by knowing the C-types of expected
arguments and return-value. So, maybe, freeze is not so useful to
you after all. Having your C-written DLL explicitly load and
initialize Python is not all that hard. Just remember that in a DLL
the main function is NOT called -- rather, DllMain is (on Windows).
For example, the following source (accompanied by the above snippet)
will implement a DLL that initializes Python, loads tryit.py (or .pyc),
and exposes the single function test_int4 (taking two integers and
returning an integer):
#include <stdio.h>
#include <Python.h>
PyObject* module_object;
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
if(ul_reason_for_call == DLL_PROCESS_ATTACH) {
Py_Initialize();
if(PyErr_Occurred()) {
PyErr_Print();
return FALSE;
}
module_object = PyImport_ImportModule("tryit");
if(PyErr_Occurred()) {
PyErr_Print();
return FALSE;
}
if(!module_object) return FALSE;
}
return TRUE;
}
Just make sure to compile this with the /MD switch (so
it will use the 'Multithreaded DLL' C runtime, MSVCRT.DLL).
This makes no attempt at packaging things into a single
file; three files will be needed -- this DLL, the python20.dll
(assuming you use Python 2.0 -- no reason not to) which must
reside somewhere on the PATH (normally including the same
directory in which this DLL will reside), and tryit.py (or
tryit.pyc, &c) which must reside somewhere on the PYTHONPATH.
I guess that, if having 3 files is a problem, you can,
after you're done developing and debugging, manage to pack
it back into one -- by linking Python statically to your
DLL (haven't done that in Windows, I think you must rebuild
Python from sources to achieve that) and having the Python
code reside inside your C program rather than in a separate
tryit.py (&c) file. E.g., for the latter: instead of the line:
module_object = PyImport_ImportModule("tryit");
you can substitute in the above example the codeblock:
{
PyObject* code_object = Py_CompileString(source, "tryit",
Py_file_input);
module_object = PyImport_ExecCodeModule("tryit", code_object);
Py_XDECREF(code_object);
}
with, as a program-global variable (i.e., outside the function,
and textually before it):
char source[] = "\
def test_int4(x,y):\n\
print 'test_int4 called (%s,%s)' % (x,y)\n\
return x+y\n\
\n";
However, I suggest doing this as the very last step, since
trying and modifying your Python code becomes much harder and
less convenient once you've embedded it in your C program in
this fashion!
Alex
More information about the Python-list
mailing list