如何从cygwin python调用windows dll函数?

如何从cygwin python调用windows dll函数?,python,windows,dll,cygwin,ctypes,Python,Windows,Dll,Cygwin,Ctypes,我有一个Windows python3.7函数,它使用ctypes成功调用kernel32.dll GetSystemPowerStatus函数来查询电源状态,以查看我的笔记本电脑是使用交流电还是电池供电。这是一个纯python解决方案 elif _os.name == 'posix' and _sys.platform == 'cygwin': RTLD_LOCAL = 0 # from /usr/include/dlfcn.h RTLD_LAZY = 1 RTLD_

我有一个Windows python3.7函数,它使用ctypes成功调用kernel32.dll GetSystemPowerStatus函数来查询电源状态,以查看我的笔记本电脑是使用交流电还是电池供电。这是一个纯python解决方案

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
我想将此函数移植到cygwin python3.7。开箱即用的python3 for cygwin的ctypes似乎不允许调用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行


解决了。请参见下面我自己的答案。

与您一样,我无法获取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)
这在Python2.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

感谢所有人的帮助。

请给出在cygwin'$python3.7 GetSystemPowerStatus.py中运行windows工作代码时收到的错误消息⏎ 回溯最近一次呼叫上次:⏎ 文件GetSystemPowerStatus.py,第69行,在⏎ 结果,systemPowerStatus=GetSystemPowerStatus⏎ 文件GetSystemPowerStatus.py,第57行,位于GetSystemPowerStatus中⏎ GetSystemPowerStatus=cdll.kernel32.GetSystemPowerStatus⏎ 文件/usr/lib/python3.7/ctypes/_uuinit_uu.py,第426行,在getattr中__⏎ dll=self.\u dlltypename⏎ 文件/usr/lib/python3.7/ctypes//uuuu init.py,第356行,in\uu init__⏎ self.\u handle=\u dlopenself.\u名称,模式⏎ OSError:没有这样的文件或目录⏎'使用其他格式化信息编辑问题。评论读起来显然是一团糟。令人费解的是,实际上这对我来说是可行的:ctypes.CDLL/cygdrive/c/windows/system32/user32.dll,但不适用于kernel32.dll。我得到了完全相同的错误。因此,可以从cygwin加载windows库,但不能从kernel32加载:谢谢。非常有趣。我想一定要查一下ctypes的来源。谢谢。这有点复杂。我找到了一个更好的方法。同时检查:。