223

What is the easiest way to use a DLL file from within Python?

Specifically, how can this be done without writing any additional wrapper C++ code to expose the functionality to Python?

Native Python functionality is strongly preferred over using a third-party library.

Vitality
  • 20,705
  • 4
  • 108
  • 146
Tom Hennen
  • 4,746
  • 7
  • 34
  • 45
  • @Remuze did you tag the wrong question or tag with the wrong answer? They're both python, but I see no reason why you'd find them at all similar (and I checked the revision history to make sure it wasn't somehow closer at some point in the past) – Foon Apr 22 '16 at 15:37
  • 1
    @foon hmmm yes sorry, I meant to flag another question as duplicate and put this one :) I guess that shows how similar they are! – Trev Davies Apr 22 '16 at 16:05

7 Answers7

185

For ease of use, ctypes is the way to go.

The following example of ctypes is from actual code I've written (in Python 2.5). This has been, by far, the easiest way I've found for doing what you ask.

import ctypes

# Load DLL into memory.

hllDll = ctypes.WinDLL ("c:\\PComm\\ehlapi32.dll")

# Set up prototype and parameters for the desired function call.
# HLLAPI

hllApiProto = ctypes.WINFUNCTYPE (
    ctypes.c_int,      # Return type.
    ctypes.c_void_p,   # Parameters 1 ...
    ctypes.c_void_p,
    ctypes.c_void_p,
    ctypes.c_void_p)   # ... thru 4.
hllApiParams = (1, "p1", 0), (1, "p2", 0), (1, "p3",0), (1, "p4",0),

# Actually map the call ("HLLAPI(...)") to a Python name.

hllApi = hllApiProto (("HLLAPI", hllDll), hllApiParams)

# This is how you can actually call the DLL function.
# Set up the variables and call the Python name with them.

p1 = ctypes.c_int (1)
p2 = ctypes.c_char_p (sessionVar)
p3 = ctypes.c_int (1)
p4 = ctypes.c_int (0)
hllApi (ctypes.byref (p1), p2, ctypes.byref (p3), ctypes.byref (p4))

The ctypes stuff has all the C-type data types (int, char, short, void*, and so on) and can pass by value or reference. It can also return specific data types although my example doesn't do that (the HLL API returns values by modifying a variable passed by reference).


In terms of the specific example shown above, IBM's EHLLAPI is a fairly consistent interface.

All calls pass four void pointers (EHLLAPI sends the return code back through the fourth parameter, a pointer to an int so, while I specify int as the return type, I can safely ignore it) as per IBM's documentation here. In other words, the C variant of the function would be:

int hllApi (void *p1, void *p2, void *p3, void *p4)

This makes for a single, simple ctypes function able to do anything the EHLLAPI library provides, but it's likely that other libraries will need a separate ctypes function set up per library function.

The return value from WINFUNCTYPE is a function prototype but you still have to set up more parameter information (over and above the types). Each tuple in hllApiParams has a parameter "direction" (1 = input, 2 = output and so on), a parameter name and a default value - see the ctypes doco for details

Once you have the prototype and parameter information, you can create a Python "callable" hllApi with which to call the function. You simply create the needed variable (p1 through p4 in my case) and call the function with them.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Yep, ctypes is great. Python has been blessed with a great built-in (since 2.5) way to access code in DLLs. ctypes is so easy to use that you have to think twice before writing real extensions, instead of just providing a pure Python module that uses ctypes to interface your DLL. – Eli Bendersky Nov 01 '08 at 06:35
  • 2
    Hello, it may be a long time since someone replied here but I wanted to know something to make this work exactly for my program. Could you tell me what is "HLLAPI" in this? Also, if I want to access my dll with a function "void BoxProperties(double L, double H, double W,double &A, double &V);" could you suggest me what changes should I make to the above code in order to make it work? Cheers. – Neophile Sep 09 '11 at 09:53
  • 5
    What exactly does `hllApiParams` do? What is the point of those tuples? It's hard to match up some of the things in this example with the documentation. – Jonathon Reinhart Jan 23 '12 at 00:18
  • Note: It appears you don't actually need it. You can simply ignore the 2nd parameter when calling `hllApiProto` in this example. – Jonathon Reinhart Jan 23 '12 at 00:52
  • 1
    @JonathonReinhart, I've fleshed out the specific example a bit with some text at the bottom. Hopefully, that explains it a little better. If not, let me know and I'll try again :-) – paxdiablo Jan 23 '12 at 01:16
  • 1
    excellent answer, helps a lot 6 years after :) I would have put a +100 if I could have done it! – Colonel Beauvel Feb 05 '15 at 10:41
  • Is this example a wrapper? (I'm new in python and I wish to use a dll in it) – Alexander Leon VI Oct 06 '15 at 16:35
  • 3
    This is super confusing from a ctypes newcomers perspective.. Not exactly sure what is going on, even with the explanation. – RattleyCooper Apr 01 '16 at 17:26
  • @DuckPuncher, if you'd like to point out which *part* of the answer is causing you trouble, I'll be happy to try and fix it. If, however, it's just general confusion and you can't tie it to some specific aspect, you probably want to do a little more research on the ctypes subject (e.g., follow the first link to the Python docs). An SO answer is, by the necessity of keeping size down, less comprehensive that a massive document set like that linked to. – paxdiablo Apr 02 '16 at 09:08
  • @paxdiablo, well, I have seen other examples that use a much simpler syntax. Is there any specific reason it needs to be done this way instead of something like [this](http://stackoverflow.com/a/5253910/2930045)? It seems to be a lot more straight forward, and it's not an entire document. Maybe I'm just missing something. Like I said, I'm new. I don't mean any offense whatsoever. – RattleyCooper Apr 02 '16 at 17:57
  • @paxdiablo Communicating with IBM Personal Comm from Python is exact what I'm look for. However, when I ran the last step (on function 1), it takes forever to finish. Could you please help me to connect to an Emulator? – Catiger3331 Jul 09 '18 at 21:53
  • @paxdiablo I followed exactly what you wrote but when I tried to connect to a presentation space, the function 1 keeps returning 9 (an error has occurred.) Is there something that I'm missing? – Catiger3331 Jul 10 '18 at 13:48
  • 1
    @yughred, unfortunately, I left IBM quite a while ago so no longer have access to a ready PComm to test it against. From memory, the only error I ever saw from this was when trying to use a PSID that was already in use, but your error 9 hints at something more fundamental, possibly an environment setup issue. Sorry I can't help more, perhaps it would be worthwhile seeing if you can find logs somewhere, something that gives a little more info than "a system error occurred" :-) Other than that, the best I can do is suggest you recheck all parameters being sent to the function. – paxdiablo Jul 10 '18 at 13:59
  • 1
    @paxdiablo Thanks for the reply and suggestions. It's amazing that you still keep track of your post after all these years. Yes, I'll try to locate a log and see what I can do from there. Thanks again. – Catiger3331 Jul 10 '18 at 14:42
90

This page has a very simple example of calling functions from a DLL file.

Paraphrasing the details here for completeness:

It's very easy to call a DLL function in Python. I have a self-made DLL file with two functions: add and sub which take two arguments.

add(a, b) returns addition of two numbers
sub(a, b) returns substraction of two numbers

The name of the DLL file will be "demo.dll"

Program:

from ctypes import*
# give location of dll
mydll = cdll.LoadLibrary("C:\\demo.dll")
result1= mydll.add(10,1)
result2= mydll.sub(10,1)
print("Addition value:"+result1)
print("Substraction:"+result2)

Output:

Addition value:11
Substraction:9
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
atul
  • 901
  • 6
  • 2
  • 2
    The link in this answer is broken. – Kaliber64 Feb 19 '13 at 04:15
  • 12
    If the link doesn't work for you do not worry, it is a direct copy paste. You are not missing any info. – marsh Jun 16 '15 at 14:16
  • I built a dynamic link library (.dll) of my own in C++ by Visual Studio. However, when I tried to use it in Python when I had it compiled in x64 mode, I received an error about "This is not a valid Win32 application". I recompiled the dll in x86 mode and the error message disappeared. – Meisam Rasouli Jun 23 '22 at 10:12
17

Building a DLL and linking it under Python using ctypes

I present a fully worked example on how building a shared library and using it under Python by means of ctypes. I consider the Windows case and deal with DLLs. Two steps are needed:

  1. Build the DLL using Visual Studio's compiler either from the command line or from the IDE;
  2. Link the DLL under Python using ctypes.

The shared library

The shared library I consider is the following and is contained in the testDLL.cpp file. The only function testDLL just receives an int and prints it.

#include <stdio.h>
​
extern "C" {
​
__declspec(dllexport)
​
void testDLL(const int i) {
    printf("%d\n", i);
}
​
} // extern "C"

Building the DLL from the command line

To build a DLL with Visual Studio from the command line run

"C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\vsdevcmd"

to set the include path and then run

cl.exe /D_USRDLL /D_WINDLL testDLL.cpp /MT /link /DLL /OUT:testDLL.dll

to build the DLL.

Building the DLL from the IDE

Alternatively, the DLL can be build using Visual Studio as follows:

  1. File -> New -> Project;
  2. Installed -> Templates -> Visual C++ -> Windows -> Win32 -> Win32Project;
  3. Next;
  4. Application type -> DLL;
  5. Additional options -> Empty project (select);
  6. Additional options -> Precompiled header (unselect);
  7. Project -> Properties -> Configuration Manager -> Active solution platform: x64;
  8. Project -> Properties -> Configuration Manager -> Active solution configuration: Release.

Linking the DLL under Python

Under Python, do the following

import os
import sys
from ctypes import *

lib = cdll.LoadLibrary('testDLL.dll')

lib.testDLL(3)
Vitality
  • 20,705
  • 4
  • 108
  • 146
6

Maybe with Dispatch:

from win32com.client import Dispatch

zk = Dispatch("zkemkeeper.ZKEM") 

Where zkemkeeper is a registered DLL file on the system... After that, you can access functions just by calling them:

zk.Connect_Net(IP_address, port)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Carlos Gomez
  • 61
  • 1
  • 1
6

ctypes can be used to access dlls, here's a tutorial:

http://docs.python.org/library/ctypes.html#module-ctypes

monkut
  • 42,176
  • 24
  • 124
  • 155
3

ctypes will be the easiest thing to use but (mis)using it makes Python subject to crashing. If you are trying to do something quickly, and you are careful, it's great.

I would encourage you to check out Boost Python. Yes, it requires that you write some C++ code and have a C++ compiler, but you don't actually need to learn C++ to use it, and you can get a free (as in beer) C++ compiler from Microsoft.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
David Nehme
  • 21,379
  • 8
  • 78
  • 117
2

If the DLL is of type COM library, then you can use pythonnet.

pip install pythonnet

Then in your python code, try the following

import clr
clr.AddReference('path_to_your_dll')

# import the namespace and class

from Namespace import Class

# create an object of the class

obj = Class()

# access functions return type using object

value = obj.Function(<arguments>)


then instantiate an object as per the class in the DLL, and access the methods within it.

Torch
  • 51
  • 1
  • 9
sattva_venu
  • 677
  • 8
  • 22