Reputation: 63
I am using Python 3.6.0 and ctypes to access functions exported from a .dll. I want to access the functions by instantiating function prototype with a paramflags parameter. One of the functions in the .dll is defined static so it is not exported. However the .dll also contains a function pointer that points to that function and that is exported.
This is a simplified version of the .dll
typedef void ( *function ) ( int *output, int input );
__declspec( dllexport ) void two( int *output, int input );
__declspec( dllexport ) extern const function four;
void two( int *output, int input ) {
*output = 2 * input;
}
static void three( int *output, int input ) {
*output = 3 * input;
}
const function four = three;
and this is my Python code
import ctypes
dll = ctypes.cdll.test
# calling two( ) as an attribute of dll
two = dll.two
two.argtypes = [ ctypes.POINTER( ctypes.c_int ), ctypes.c_int ]
two.restype = None
output = ctypes.c_int( )
# output = c_long(2)
two( ctypes.byref( output ), 1 )
print( 'output =', output )
# calling two( ) by instantiating a function prototype with paramflags
function = ctypes.CFUNCTYPE( None, ctypes.POINTER( ctypes.c_int ), ctypes.c_int )
paramflags = ( ( 2, 'output' ), ( 1, 'input' ) )
two = function( ( 'two', dll ), paramflags )
# output = 2
output = two( 1 )
print( 'output =', output )
# I can call four( ) using in_dll( )
four = function.in_dll( dll, 'four' )
output = ctypes.c_int( )
# output = c_long(3)
four( ctypes.byref( output ), 1 )
print( 'output =', output )
# but not as an attribute of dll
four = dll.four
four.argtypes = [ ctypes.POINTER( ctypes.c_int ), ctypes.c_int ]
four.restype = None
output = ctypes.c_int( )
# this results in a "OSError: exception: access violation writing 0x6C0C3064"
four( ctypes.byref( output ), 1 )
print( 'output =', output )
# nor by instantiating a function prototype
paramflags = ( ( 2, 'output' ), ( 1, 'input' ) )
four = function( ( 'four', dll ), paramflags )
# this results in a "OSError: exception: access violation writing 0x6C0C3064"
output = four( 1 )
print( 'output =', output )
I can access two( ) as an attribute of dll, and by instantiating a function prototype. However when I try to do that with four( ) I get "OSError: exception: access violation writing 0x6C0C3064". After a lot of experimenting I found out that I can access four( ) using in_dll( ), but then I can't apply the paramflags functionality.
Is there any way to access four( ) and use paramflags?
Note: I don't want to change the dll (it's not part of my project) and am trying to solve it on the Python side.
Upvotes: 4
Views: 1719
Reputation: 177725
I played with this awhile but since the way to instantiate a function with paramflags
requires an exported function name and DLL in the syntax, it doesn't account for exported global function pointers.
Of course, you can get the same behavior with a little work by defining a wrapper to allocate and return the output parameter:
_four = function.in_dll( dll, 'four' )
def four(input):
output = ctypes.c_int()
_four(output,input)
return output.value
output = four(5)
print('output =',output)
Upvotes: 1
Reputation: 779
"I am using Python 3.6.0 and ctypes to access functions exported from a .dll." I Think the problem is the following.
This
typedef void ( *function ) ( int *output, int input );
__declspec( dllexport ) extern const function four;
doesn't actually export a function from the dll, but only a pointer to a typedef'ed function, that is declared extern. In the end the Symbol Exporter has nothing really to work with. If you look for example in the generated lib after the build, you find a clean refenrence to two, but four is messed up.
If you declare the four function regulary
__declspec( dllexport ) const void four( int *output, int input );
and then define the function regulary
const void four( int *output, int input ) {
*output = 3 * input;
}
then you should be able to access four() and use paramflags.
Upvotes: 0