How to call a DLL in a Windows environment using Python-how to use the ctypes Library

Source: Internet
Author: User
Tags 04x guid generator

Author: magictong)

P.s. The layout is out of order. Let's make the layout here. By the way, we can change some of the incorrect words.

2011-08-04

In python, C needs to supplement efficiency in some cases. In actual applications, some data needs to be interacted. Using the ctypes module in Python, you can easily call windows DLL (including files such as so in Linux). The following describes this module in detail (taking the Windows platform as an example ), of course, I suppose you have no problem with how to write a DLL in windows.

Introduce the ctypes Library

from ctypes import * 

Suppose you already have a DLL named add. DLL), and The dll has an export function that complies with the cdecl (the call convention is emphasized here because the stdcall call convention and the cdecl call Convention declare, the loading functions used for loading in Python are different, which will be described later) Call the agreed export function add.
Create a python file dllcall. py for testing:

from ctypes import *dll = CDLL("add.dll")print dll.Add(1, 102)

Result: 103

The above is a simple example. The following describes the call process:
1. Load DLL
As mentioned above, when loading a function, it depends on the call conventions that you want to call.
Stdcall call Conventions: Two Loading Methods

Objdll = ctypes.windll.LoadLibrary("dllpath")Objdll = ctypes.WinDLL("dllpath") 

Cdecl call Convention: there are also two loading methods

Objdll = ctypes. cdll. loadlibrary ("dllpath") objdll = ctypes. cdll ("dllpath") In fact, Windll and cdll are respectively the Windll class and cdll class objects.


2. Call methods in DLL
When loading a DLL in 1, a DLL object is returned (assuming the name is objdll). With this object, you can call the methods in the DLL.
E.g. if the dll contains a method named add (Note that if the method declared by stdcall is not the export function declared by the def file or the extern "C" declaration, the compiler will modify the function name. Please note that I understand it .)
Call: nret = objdll. Add (12, 15) to complete a call.

It seems that the call is very simple. Don't just look at the representation. Haha, this is because the Add function is too simple. Now suppose the function requires you to input an int type pointer (int *), it can be implemented through the byref keyword in the library. Assume that the third parameter of the currently called function is an int type pointer.

intPara = c_int(9)dll.sub(23, 102, byref(intPara))print intPara.value

If you want to input a char buffer pointer and buffer length, there are at least four methods:

# Method 1 szpara = create_string_buffer ('/0' * 100) DLL. printinfo (byref (szpara), 100); print szpara. value # method 2 sbuf = 'aaaaaaaaaabbbbbbbbbbbbbbbbb' pstr = c_char_p () pstr. value = sbuf # pvoid = ctypes. cast (pstr, ctypes. c_void_p ). valuedll. printinfo (pstr, Len (pstr. value) print pstr. value # method 3 strma = "/0" * 20 funprint = DLL. printinfofunprint. argtypes = [c_char_p, c_int] # funprint. restypes = c_void_pnrst = funprint (strma, Len (strma) print strma, Len (strma) # method 4pstr2 = c_char_p ("/0") print pstr2.value # pvoid = ctypes. cast (pstr, ctypes. c_void_p ). valuedll. printinfo (pstr2, Len (pstr. value) print pstr2.value


3. Type ing table implemented in C basic type and ctypes

Ctypes Data Type C data type
C_char char
C_short short
C_int int
C_long long
C_ulong unsign long
C_float float
C_double double
C_void_p void
The corresponding pointer type is followed by "_ p", for example, int * Is c_int_p.
Classes are required to implement the structure in the C language in Python.

4. The function in the DLL returns a pointer.
Although this is not a good programming method, the processing method in this case is also very simple. In fact, the returned addresses are all, converting them to the corresponding Python type, and then accessing them through the value attribute.

pchar = dll.getbuffer()szbuffer = c_char_p(pchar)print szbuffer.value


5. Process struct types in C
Why do we propose this separately? Because this is the most troublesome and complex. In python, declare a structure similar to C, and use classes. This class must inherit from the structure.
Let's take a look at a simple example:
The DLL definition in C is as follows:

typedef struct _SimpleStruct{    int    nNo;    float  fVirus;    char   szBuffer[512];} SimpleStruct, *PSimpleStruct;typedef const SimpleStruct*  PCSimpleStruct;extern "C"int  __declspec(dllexport) PrintStruct(PSimpleStruct simp);int PrintStruct(PSimpleStruct simp){    printf ("nMaxNum=%f, szContent=%s", simp->fVirus, simp->szBuffer);return simp->nNo;}


Python definition:

from ctypes import *class SimpStruct(Structure):    _fields_ = [ ("nNo", c_int),              ("fVirus", c_float),              ("szBuffer", c_char * 512)]dll = CDLL("AddDll.dll")simple = SimpStruct();simple.nNo = 16simple.fVirus = 3.1415926simple.szBuffer = "magicTong/0"print dll.PrintStruct(byref(simple))

The struct in the above example is very simple, but if the struct contains pointers or even pointers to the struct, the processing will be much more complicated, but Python also has corresponding processing methods, the following example is from the internet. I wanted to write it myself, so I am too lazy to write it. Just explain the problem:
The C code is as follows:

typedef struct {char words[10];}keywords; typedef struct {keywords *kws;unsigned int len;}outStruct;extern "C"int __declspec(dllexport) test(outStruct *o);int test(outStruct *o){unsigned int i = 4;o->kws = (keywords *)malloc(sizeof(unsigned char) * 10 * i);strcpy(o->kws[0].words, "The First Data");strcpy(o->kws[1].words, "The Second Data"); o->len = i;return 1;}

The Python code is as follows:

class keywords(Structure):        _fields_ = [('words', c_char *10),] class outStruct(Structure):        _fields_ = [('kws', POINTER(keywords)),                    ('len', c_int),]o = outStruct()dll.test(byref(o)) print o.kws[0].words;print o.kws[1].words;print o.len


6. Example
Let's take a look at two practical examples.
Example 1:
This is a guid generator. In fact, many third-party Python libraries already have encapsulated libraries for calling. However, you have to install that library. If you want to call some APIs directly, for python, you also need to use a third-party library. This example is relatively simple, that is, using C ++ to call the Win32 API to generate a guid, and then Python obtains the guid by calling the DLL written in C ++.
The C ++ code is as follows:

extern "C"__declspec(dllexport) char* newGUID(); char* newGUID() {     static char buf[64] = {0};     statc GUID guid;     if (S_OK == ::CoCreateGuid(&guid))      {       _snprintf(buf, sizeof(buf),"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", guid.Data1,guid.Data2,guid.Data3,guid.Data4[0], guid.Data4[1],guid.Data4[2], guid.Data4[3],guid.Data4[4], guid.Data4[5],guid.Data4[6], guid.Data4[7]);        ::MessageBox(NULL, buf, "GUID", MB_OK);       }     return (char*)buf;}

The Python code is as follows:

Def createguid (): "Create a globally unique identifier like: E06093E2-699A-4BF2-A325-4F1EADB50E18 newversion" try: # dll path strdllpath = sys. path [0] + STR (OS. SEP) + "createguid. DLL "DLL = cdll (strdllpath) B = DLL. newguid () A = c_char_p (B) failed t exception, error: print error return "" return. value


Example 2:
In this example, call the createprocessa function in kernel32.dll to start a notepad process.

#-*-Coding: UTF-8-*-from ctypes import * # define the _ process_information struct class _ process_information (structure): _ fields _ = [('hprocess', c_void_p ), ('hthread', c_void_p), ('dwprocessid', c_ulong), ('dwthreadid', c_ulong)] # define the _ startupinfo struct class _ startupinfo (structure ): _ fields _ = [('cb ', c_ulong), ('lpreserved', c_char_p), ('lpdesktop', c_char_p), ('lptitle', c_char_p ), ('dwx', c_ulong), ('dwy', c_ulong), ('dwxsize', c_ulong), ('dwysize', c_ulong), ('dwxcountchars', c_ulong ), ('dwycountchars', c_ulong), ('dwfillattribute ', c_ulong), ('dwflags', c_ulong), ('wshowwindow', c_ushort), ('cbreserved2', c_ushort ), ('lpreserved2', c_char_p), ('hstdinput', c_ulong), ('hstdoutput', c_ulong), ('hstderror ', c_ulong)] normal_priority_class = 0x00000020 # define normal_priority_classkernel32 = Windll. loadlibrary ("kernel32.dll ") # Load struct = struct # obtain the CreateProcess function address readprocessmemory = struct # obtain the readprocessmemory function address writeprocessmemory = struct # obtain the writeprocessmemory function address terminateprocess = struct # declare the struct processinfo = _ process_information () startupinfo = _ startupinfo () filename = 'C:/Windows/notepad.exe '# file address to be modified = 0x0040103c # memory address to be modified strbuf = c_char_p ("_") # buffer address bytesread = c_ulong (0) # number of bytes read buffersize = Len (strbuf. value) # buffer size # CreateProcess (filename, 0, 0, 0, 0, normal_priority_class, 0, 0, byref (startupinfo), byref (processinfo ))

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.