使用ctypes调用指向静态定义的函数的函数指针

时间:2017-02-16 19:59:29

标签: python c python-3.x dll ctypes

我使用Python 3.6.0和ctypes来访问从.dll导出的函数。我想通过使用paramflags参数实例化函数原型来访问函数。 .dll中的一个函数是静态定义的,因此不会导出。但是.dll还包含一个指向该函数并导出的函数指针。

这是.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;

这是我的Python代码

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 )

我可以访问两个()作为dll的属性,并通过实例化一个函数原型。但是,当我尝试使用four()时,我得到“OSError:exception:access violation writing 0x6C0C3064”。经过大量的实验,我发现我可以使用in_dll()访问four(),但后来我无法应用paramflags功能。

有没有办法访问four()并使用paramflags?

注意:我不想更改dl​​l(它不是我的项目的一部分)并且我试图在Python端解决它。

2 个答案:

答案 0 :(得分:1)

我玩了一段时间,但由于使用paramflags实例化函数的方法需要在语法中导出函数名和DLL,因此它不考虑导出的全局函数指针

当然,通过定义一个包装器来分配和返回输出参数,你可以通过一些工作获得相同的行为:

_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)

答案 1 :(得分:0)

“我使用Python 3.6.0和ctypes来访问从.dll导出的函数。”我认为问题如下。

typedef void ( *function ) ( int *output, int input );
__declspec( dllexport ) extern const function four;

实际上并不是从dll导出函数,而只是指向typedef'ed函数的指针,它被声明为extern。最终,Symbol Exporter没有什么可以使用的。 如果你在构建之后在生成的lib中查找示例,你会发现对2的干净重读,但是有4个被搞砸了。

如果你声明四个函数是常规的

__declspec( dllexport ) const void four( int *output, int input );

然后定义常规函数

const void four( int *output, int input ) {
    *output =  3 * input;
}

然后你应该能够访问four()并使用paramflags。