![](/img/trans.png)
[英]How do I install python on a windows machine using a cygwin terminal?
[英]How do I call a windows dll function from cygwin python?
我有一個Windows
python3.7
函數,該函數使用ctypes
成功調用kernel32.dll
GetSystemPowerStatus
函數來詢問電源狀態,以查看我的筆記本電腦是使用交流電還是電池供電。 這是一個純python解決方案。
我想將此功能移植到cygwin
python3.7
。 開箱即用, cygwin
的ctypes
python3
似乎不允許調用Windows dll。 我希望使用純python解決方案,但如有必要,我可以使用C / C ++。 有沒有人舉過一個例子?
編輯以添加代碼(第63-67行)和錯誤消息:
elif _os.name == 'posix' and _sys.platform == 'cygwin':
# c:\Windows\System32\kernel32.dll
kernel32_name = '/proc/cygdrive/c/Windows/System32/kernel32.dll'
kernel32 = CDLL(kernel32_name)
_GetSystemPowerStatus = kernel32.GetSystemPowerStatus
$ python3.7 GetSystemPowerStatus.py
Traceback (most recent call last):
File "GetSystemPowerStatus.py", line 82, in <module>
result, systemPowerStatus = GetSystemPowerStatus()
File "GetSystemPowerStatus.py", line 66, in GetSystemPowerStatus
kernel32 = CDLL(kernel32_name)
File "/usr/lib/python3.7/ctypes/__init__.py", line 356, in __init__
self._handle = _dlopen(self._name, mode)
OSError: Invalid argument
python2.7給出了相同的錯誤,但在第366行。
解決了。 請參閱下面的我自己的答案。
如您msvcrt
,我無法獲取kernel32.dll
(盡管它可以與其他DLL(例如user32
, msvcrt
, kernelbase
等)一起使用。
我發現了一種非常人為的方式...它使用kernelbase.dll(導出GetModuleHandle
)來獲取kernel32.dll
的句柄,然后使用handle可選關鍵字調用CDLL
:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import ctypes
def main():
# the idea is to load kernelbase.dll which will allow us to call GetModuleHandleW() on kernel32.dll
try:
kernel_base = ctypes.CDLL("/cygdrive/c/windows/system32/kernelbase.dll")
except OSError:
print("Can't load kernelbase.dll...")
return -1
gmhw = kernel_base.GetModuleHandleW
gmhw.argtypes = (ctypes.c_wchar_p, )
gmhw.restype = ctypes.c_void_p
# call GetModuleHandleW on kernel32.dll (which is loaded by default in the Python process)
kernel32_base_addr = gmhw("kernel32.dll")
print(f"Got kernel32 base address: {kernel32_base_addr:#x}")
# now call CDLL with optional arguments
kernel32 = ctypes.CDLL("/cygdrive/c/windows/system32/kernel32.dll", handle=kernel32_base_addr, use_last_error=True)
# test with GetSystemPowerStatus
print(f"GetSystemPowerStatus: {kernel32.GetSystemPowerStatus}")
return 0
if __name__ == "__main__":
sys.exit(main())
在發現我可以輕松加載user32.dll
,我對源文件和pdb
和ldd
進行了更多調查。 接下來是我的解決方案。
elif _os.name == 'posix' and _sys.platform == 'cygwin':
RTLD_LOCAL = 0 # from /usr/include/dlfcn.h
RTLD_LAZY = 1
RTLD_NOW = 2
RTLD_GLOBAL = 4
RTLD_NODELETE = 8
RTLD_NOLOAD = 16
RTLD_DEEPBIND = 32
kernel32_name = '/proc/cygdrive/c/Windows/System32/kernel32.dll'
kernel32 = CDLL(kernel32_name, mode=RTLD_LAZY | RTLD_NOLOAD)
_GetSystemPowerStatus = kernel32.GetSystemPowerStatus
調用該函數的常見代碼是:
_GetSystemPowerStatus.restype = c_bool
_GetSystemPowerStatus.argtypes = [c_void_p,]
_systemPowerStatus = _SystemPowerStatus() # not shown, see ctypes module doc
result = _GetSystemPowerStatus(byref(_systemPowerStatus))
return result, SystemPowerStatus(_systemPowerStatus)
在Python 2.7、3.6和3.6上可以正常工作
$ uname -a
CYGWIN_NT-10.0 host 3.0.1(0.338/5/3) 2019-02-20 10:19 x86_64 Cygwin
感謝所有人的幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.