How can I use a DLL file from Python?
Asked Answered
P

6

227

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.

Patmos answered 31/10, 2008 at 2:1 Comment(2)
@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)Wale
@foon hmmm yes sorry, I meant to flag another question as duplicate and put this one :) I guess that shows how similar they are!Wynne
G
188

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.

Guaranty answered 31/10, 2008 at 2:43 Comment(14)
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.Terrazzo
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.Sublime
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.Presa
Note: It appears you don't actually need it. You can simply ignore the 2nd parameter when calling hllApiProto in this example.Presa
@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 :-)Guaranty
excellent answer, helps a lot 6 years after :) I would have put a +100 if I could have done it!Nerine
Is this example a wrapper? (I'm new in python and I wish to use a dll in it)Aster
This is super confusing from a ctypes newcomers perspective.. Not exactly sure what is going on, even with the explanation.Belch
@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.Guaranty
@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? 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.Belch
@Guaranty 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?Pound
@Guaranty 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?Pound
@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.Guaranty
@Guaranty 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.Pound
J
92

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
Johnsiejohnson answered 4/7, 2010 at 6:28 Comment(4)
The link in this answer is broken.Karr
If the link doesn't work for you do not worry, it is a direct copy paste. You are not missing any info.Strawflower
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.Griddlecake
can the path to the .dll file be a relative pathname?Hypocrisy
Z
18

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)
Zoba answered 4/4, 2019 at 7:4 Comment(1)
What if the DLL in a python package? How do I access it?Exanimate
C
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)
Comatulid answered 17/6, 2013 at 21:38 Comment(1)
I'm working on this zkemkeeper.ZKEM, do you know how I can get realtime events in python?Tyrr
G
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.

Gestapo answered 31/10, 2008 at 2:24 Comment(0)
I
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.

Infiltrate answered 30/5, 2020 at 15:25 Comment(2)
Please note: Current version of pythonnet doesn't work with .NET Core (github.com/pythonnet/pythonnet/issues/984)Grimes
@gdyrrahitis, in my case I had used .NET framework, thanks for the info.Infiltrate

© 2022 - 2024 — McMap. All rights reserved.