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