调用Windows DLL的python不可知代码
我所要做的就是想出一个与python无关的调用Windows DLL的代码。我所说的python不可知论是指我希望它在python 2、python 3、cygwin CPython和Windows CPython中都能同样出色地工作。最后,我还希望它也能在Jython和IronPython中工作,以及在MSYS2中工作 我读过吴永伟关于MSVC和MinGW的Stdcall和DLL工具的非常好的文章,以及其他几篇stackoverflow文章——我的目标似乎并不那么普遍 经过反复试验,我提出了两个似乎可行的想法,但我不确定它们是否真的解决了吴永伟文章中涉及的“呼叫约定”ABI问题 在Python 2和3以及Cygwin CPython和Windows CPython中,第一种工作方式是:调用Windows DLL的python不可知代码,python,python-3.x,windows,dll,python-2.x,Python,Python 3.x,Windows,Dll,Python 2.x,我所要做的就是想出一个与python无关的调用Windows DLL的代码。我所说的python不可知论是指我希望它在python 2、python 3、cygwin CPython和Windows CPython中都能同样出色地工作。最后,我还希望它也能在Jython和IronPython中工作,以及在MSYS2中工作 我读过吴永伟关于MSVC和MinGW的Stdcall和DLL工具的非常好的文章,以及其他几篇stackoverflow文章——我的目标似乎并不那么普遍 经过反复试验,我提出了两
import os, sys, platform, re
'''Make Wide'''
def makeWide(instring):
outstring=''
python_version_int = sys.version_info.major * 1000000 + sys.version_info.minor * 1000 + sys.version_info.micro
for idx in range(0,len(instring)):
if python_version_int < 3000000:
outstring=outstring+instring[idx:idx+1]+chr(0)
else:
outstring=outstring+instring[idx:idx+1]
return outstring
python_platform_short=re.sub(r"_.*$","", platform.system() , 1 ).lower();
Windows_System32_User32_DLL_win = 'C:/Windows/System32/User32.dll'
Windows_System32_User32_DLL_cyg = '/cygdrive/c/Windows/System32/User32.dll'
MB_ABORTRETRYIGNORE = c_long(2)
Windows_System32_User32_DLL = Windows_System32_User32_DLL_win
if python_platform_short == 'cygwin':
Windows_System32_User32_DLL = Windows_System32_User32_DLL_cyg
if python_platform_short == 'cygwin':
user32=cdll.LoadLibrary(Windows_System32_User32_DLL)
else:
user32=windll.LoadLibrary(Windows_System32_User32_DLL)
user32_MessageBoxW=getattr(user32,"MessageBoxW")
message_box_window = c_void_p(0) # HWND
message_box_title = c_wchar_p('Hello')
message_box_message = c_wchar_p('Hello world!!')
message_box_flags = MB_ABORTRETRYIGNORE
user32_MessageBoxW(message_box_window, message_box_message, message_box_title, message_box_flags )
这尝试使用六和和编码(“utf-16LE”)来解决Python2和Python3中的字符串差异,并使用cffi调用dll。同样,我不太清楚这是否解决了堆栈问题
第三种可以让我直接解决ABI和堆栈问题的方法是使用pycca深入到汇编,但我还没有学到足够的x86汇编来尝试这一点——尽管我已经阅读了有关调用约定的nasm文档和相关的wikipedia文章。我认为我将能够让Jython使用JNA工作,但我仍在学习IronPython和相关的python包
有人能帮我使用cffi、ctypes或Pyca方法吗?对IronPython或Jython有什么建议吗
from cffi import FFI
import six
class Win:
def message_box(self, hwnd, lptext, lpcaption, utype):
ffi = FFI()
cdefStr="""
int __stdcall MessageBoxW(void * hWnd, const char16_t * lpText, const char16_t * lpCaption, unsigned int uType);
"""
print("DEBUG : cdefStr = " + cdefStr )
ffi.cdef( cdefStr );
user32 = ffi.dlopen('C:\\Windows\\System32\\user32.dll')
if( hwnd == 0 ):
hwnd=ffi.NULL;
textSize=len(lpcaption)
lpcapForCType = "const char16_t[" + str(textSize+2) + "]"
lpcapForC = ffi.new( lpcapForCType )
for i in range( 0 , textSize ):
lpcapForC[i] = six.unichr( six.indexbytes( six.ensure_binary( lpcaption.encode("utf-16LE") ) ,(i*2)) + 256 * six.indexbytes( six.ensure_binary( lpcaption.encode("utf-16LE") ) ,(i*2)+1) )
lpcapForC[textSize] = six.unichr(0)
textSize=len(lptext)
lptextForC = ffi.new("const char16_t[" + str( textSize + 2 ) + "]" )
for i in range(0,textSize):
lptextForC[i] = six.unichr( six.indexbytes( six.ensure_binary( lptext.encode("utf-16LE") ) ,(i*2)) + 256 * six.indexbytes( six.ensure_binary( lptext.encode("utf-16LE") ) ,(i*2)+1) )
lpcapForC[textSize] = six.unichr(0)
utype=ffi.cast("unsigned int",utype);
user32.MessageBoxW(hwnd, lptextForC, lpcapForC, utype)
msg = six.u("Test with umlaut: ") + six.unichr(0xe4)
w = Win()
w.message_box(0, msg, msg, 0)