Ctypes calls dll and ctypesdll
1. Load Windows API and C Runtime Library
First look at the example
From ctypes import * u32 = windll. loadLibrary ('user32. dll ') # Load user32.dllu32. messageBoxW (0, u 'content', u 'title', 0) crt = cdll. loadLibrary ('msvcrt. dll ') # load the C Runtime crt. printf ('Hello world! \ N ')
Call C library to use cdll, while call Windows API to use windll.
The difference between cdll and windll is that the calling rules for Windows API and C library functions are different. The former follows _ stdcall and the latter follows _ cdecl.
_ Cdecl is short for C Declaration, which indicates the default function call specification of the C compiler. In this way, the caller is responsible for clearing the parameter stack. For example, in VC, if no modifier is added before the function, the default value is _ cdecl.
_ Stdcall is short for Standard Call. In this way, the called function is responsible for clearing the parameter stack. In VC, if _ stdcall is modified before the function, this type is compiled.
All Windows APIs use _ stdcall. Because Windows APIs are called by various languages in various compilers, if the _ cdecl method is used, the stack structure used in various compilers may be different, therefore, we cannot guarantee that each of the compilers can properly clean up the parameter stacks generated by Windows APIs. In the _ stdcall mode, the caller can clear the parameter stack by himself to avoid the above troubles.
In Windows, the LoadLibrary () parameter may not include the extension. There is also a simpler method, for example, the following three are equivalent:
From ctypes import * windll. loadLibrary ('user32. dll '). messageBoxW (0, u'content', u'title', 0) windll. loadLibrary ('user32 '). messageBoxW (0, u'content', u'title', 0) windll. user32.MessageBoxW (0, u'content', u'title', 0)The same is true for the following three items:
from ctypes import *cdll.LoadLibrary('msvcrt.dll').printf('hello world !\n')cdll.LoadLibrary('msvcrt').printf('hello world !\n')cdll.msvcrt.printf('hello world !\n')
2. implicit type conversion
Int, str, unicode, these three types can be passed directly as parameters, do not specify the corresponding C type
from ctypes import *cdll.msvcrt.printf('%d, %s\n', 100, 'abc')
3. Explicit type conversion
Int, str, and unicode types must be explicitly converted when used as parameters, indicating the corresponding C type
from ctypes import *cdll.msvcrt.printf('%.2f\n', c_double(3.14))
4. pointer and reference
Byref () can reference the memory address, which is equivalent &
from ctypes import *i = c_int(0)cdll.msvcrt.sscanf('100', '%d', byref(i))print i.valuePointer () can also achieve the same effect
from ctypes import *i = c_int(0)cdll.msvcrt.sscanf('100', '%d', pointer(i))print i.valueThe difference between the two is that pointer () constructs a pointer object, and byref () is just a function, so the overhead of byref () is small.
If it is only used to pass parameters, it is enough to use byref.
5. String pointer
Use create_string_buffer () and create_unicode_buffer ()
From ctypes import * s = create_string_buffer ('abc') # Initial value abccdll. msvcrt. sscanf ('def ',' % s', s) print s. value # def
6. Callback Function
To test the callback function, first write a test. dll. below is the C code
#include <stdio.h> typedef void __stdcall (*MyCallback)(int);__declspec(dllexport) void __stdcall TestMyCallback( int i, MyCallback mycallback){ printf("TestMyCallback:%d\n", i); mycallback(i*10);}The above function accepts two parameters: the first is the integer variable I, and the second is a callback function.
Print the variable I first, and then pass I * 10 to the callback function.
The (_ declspec (dllexport) keyword is used to export a function from a dll. For details, see here)
The following Python code implements the callback function and passes it to test. TestMyCallbackPython
From ctypes import * def mycallback (I): print 'mycallback: ', ic_mycallback = WINFUNCTYPE (None, # Return Value Type None represents void c_int # first parameter type int) (mycallback) # The Python function windll to be packaged is enclosed in brackets. test. testmycallback( 100, c_mycallback)
The usage of WINFUNCTYPE includes two steps:
- First, declare a C function prototype.
C_function_type = WINFUNCTYPE (return value type, first parameter type, second parameter type ...)
- Then use this prototype to encapsulate the Python function.
C_function = c_function_type (Python function)
WINFUNCTYPE complies with _ stdcall call specifications. The corresponding version of _ cdecl is CFUNCTYPE.
Python ctypes Call dll parameter conversion problems
From ctypes import *
Code = c_char_p ('')
Market = c_int (10)
Dll = windll. LoadLibrary ("./hello. dll ")
Print dll. GetStockMin (code, market)
Try it
An error is returned when python calls a function in the dll.
It seems that you have not loaded the DLL in the code.
In addition, it may be inappropriate for you to directly rewrite python memory in c. It is usually constructed in C and then returned to python.
From the perspective of your program, after calling Thin, your Variable p seems to have become a null pointer.
Ctypes Call DLL is usually prepared by others, and there is no way to call it by yourself. There are a lot of troubles here.
If you write your own code, we recommend that you use the cython module. It is easy to implement interfaces. You don't have to worry about the encapsulation of these variable types and interfaces.
In addition, the dll seems to have something to do with the compiler. It may be easier to use VC. Using BC or GCC is troublesome.
There is also a version issue, 64-bit and 32-bit cannot be used.
In principle, it is not impossible for you to use this method. It is possible that you have not made any mistakes. For example, compile parameters. You can try to use return type to bring data back. Instead of writing memory with pointers.
Because p is a constant, it is very likely that it will not be rewritten in the calling mechanism.