Python 3.4上的GetProcAddress奇怪行为

时间:2015-10-16 14:42:10

标签: python python-2.7 python-3.x winapi ctypes

在Python 2.7.10上:

>>> from ctypes import windll
>>> windll.kernel32.GetProcAddress(windll.kernel32.GetModuleHandleA('kernel32'), 'LoadLibraryW')

返回非null结果。但是Python 3.X上的相同内容始终返回null。

>>> from ctypes import windll
>>> windll.kernel32.GetProcAddress(windll.kernel32.GetModuleHandleA('kernel32'), 'LoadLibraryA')
0
# and other variants
>>> windll.kernel32.GetProcAddress(windll.kernel32.GetModuleHandleA('kernel32'), 'LoadLibraryW')
0
>>> windll.kernel32.GetProcAddress(windll.kernel32.GetModuleHandleW('kernel32'), 'LoadLibraryA')
0
>>> windll.kernel32.GetProcAddress(windll.kernel32.GetModuleHandleW('kernel32'), 'LoadLibraryW')
0

出了什么问题以及如何解决(如果可能的话)?

1 个答案:

答案 0 :(得分:1)

GetProcAddress在处理函数名字符串方面有点不寻常。由于导出的函数名称始终使用8位文本进行编码,因此过程名称参数的类型为LPCSTR

Python 2.7字符串类型str不是Unicode,当传递给ctypes时,默认将文本编码为8位。 Python 3.x字符串类型是Unicode,当传递给ctypes时,默认将文本编码为16位。因此失败了。

使用argtypesrestype准确了解类型并解决此问题。

>>> from ctypes import * # just for this answer, to save typing
>>> GetModuleHandle = windll.kernel32.GetModuleHandleW
>>> GetModuleHandle.argtypes = [c_wchar_p]
>>> GetModuleHandle.restype = c_void_p
>>> kernel32 = GetModuleHandle('kernel32')
>>> kernel32
2004418560
>>> 2004418560
2004418560
>>> GetProcAddress = windll.kernel32.GetProcAddress
>>> GetProcAddress.argtypes = [c_void_p, c_char_p]
>>> GetProcAddress.restype = c_void_p
>>> LoadLibraryW = GetProcAddress(kernel32, b'LoadLibraryW') # force 8 bit encoding
>>> LoadLibraryW
2004509856