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

时间:2019-03-03 05:37:20

标签: python windows dll cygwin ctypes

我有一个Windows python3.7函数,该函数使用kernel32.dll成功调用了GetSystemPowerStatus ctypes函数,以询问电源状态以查看笔记本电脑是否开启交流电或电池电源。这是一个纯python解决方案。

我想将此功能移植到cygwin python3.7。现成的python3的{​​{1}}的{​​{1}}似乎不允许调用Windows dll。我希望使用纯python解决方案,但如有必要,我可以使用C / C ++。有人有这样做的例子吗?

编辑后添加代码(第63-67行)和错误消息:

cygwin

python2.7给出了相同的错误,但在第366行。

已解决。请在下面查看我自己的答案。

2 个答案:

答案 0 :(得分:0)

正如您所知,我无法获得kernel32.dll(尽管它可以与user32msvcrtkernelbase等其他DLL一起使用)

我发现了一种非常人为的方法...它使用kernelbase.dll(导出GetModuleHandle)来获取kernel32.dll的句柄,然后使用该句柄调用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())

答案 1 :(得分:-1)

在发现我可以轻松加载user32.dll之后,我对源和pdbldd进行了更多研究。接下来是我的解决方案。

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

感谢大家的帮助。