从Python 3调用Windows API时句柄无效

从Python 3调用Windows API时句柄无效,python,winapi,ctypes,Python,Winapi,Ctypes,以下代码在Python 2中运行良好: import ctypes def test(): OpenSCManager = ctypes.windll.advapi32.OpenSCManagerA CloseServiceHandle = ctypes.windll.advapi32.CloseServiceHandle handle = OpenSCManager(None, None, 0) print(hex(handle)) ass

以下代码在Python 2中运行良好:

import ctypes

def test():
    OpenSCManager      = ctypes.windll.advapi32.OpenSCManagerA
    CloseServiceHandle = ctypes.windll.advapi32.CloseServiceHandle

    handle = OpenSCManager(None, None, 0)
    print(hex(handle))
    assert handle, ctypes.GetLastError()
    assert CloseServiceHandle(handle), ctypes.GetLastError()

test()
它在Python 3中不起作用:

0x40d88f90
Traceback (most recent call last):
  File ".\test1.py", line 12, in <module>
    test()
  File ".\test1.py", line 10, in test
    assert CloseServiceHandle(handle), ctypes.GetLastError()
AssertionError: 6
0x40d88f90
回溯(最近一次呼叫最后一次):
文件“\test1.py”,第12行,在
测试()
文件“\test1.py”,测试中的第10行
断言CloseServiceHandle(handle),ctypes.GetLastError()
断言者错误:6
6表示无效句柄

此外,Python 2中检索到的句柄似乎是较小的数字,例如0x100ffc0。它不是
CloseServiceHandle
的特定功能。此句柄不能与任何服务函数一起使用


这两个Python版本都是64位本机Windows Python。

您应该使用
argtypes
restype
,否则所有参数默认为int,并在64位中截断。另外,您不应该直接调用
GetLastError
,而应该使用
ctypes.get\u last\u error()
缓存上一个错误代码(执行调用后,解释器可能调用了windows API,您无法确定)

下面是一个工作示例:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import ctypes


def test():
    advapi32 = ctypes.WinDLL("advapi32", use_last_error=True)
    OpenSCManager = advapi32.OpenSCManagerA
    OpenSCManager.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_ulong]
    OpenSCManager.restype = ctypes.c_void_p

    CloseServiceHandle = advapi32.CloseServiceHandle
    CloseServiceHandle.argtypes = [ctypes.c_void_p]
    CloseServiceHandle.restype = ctypes.c_long

    handle = OpenSCManager(None, None, 0)
    if not handle:
        raise ctypes.WinError(ctypes.get_last_error())
    print(f"handle: {handle:#x}")

    result = CloseServiceHandle(handle)
    if result == 0:
        raise ctypes.WinError(ctypes.get_last_error())

def main():
    test()


if __name__ == "__main__":
    sys.exit(main())

您应该使用
argtypes
restype
否则所有参数都默认为int,并以64位截断。另外,您不应该直接调用
GetLastError
,而应该使用
ctypes.get\u last\u error()
缓存上一个错误代码(执行调用后,解释器可能调用了windows API,您无法确定)

下面是一个工作示例:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import ctypes


def test():
    advapi32 = ctypes.WinDLL("advapi32", use_last_error=True)
    OpenSCManager = advapi32.OpenSCManagerA
    OpenSCManager.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_ulong]
    OpenSCManager.restype = ctypes.c_void_p

    CloseServiceHandle = advapi32.CloseServiceHandle
    CloseServiceHandle.argtypes = [ctypes.c_void_p]
    CloseServiceHandle.restype = ctypes.c_long

    handle = OpenSCManager(None, None, 0)
    if not handle:
        raise ctypes.WinError(ctypes.get_last_error())
    print(f"handle: {handle:#x}")

    result = CloseServiceHandle(handle)
    if result == 0:
        raise ctypes.WinError(ctypes.get_last_error())

def main():
    test()


if __name__ == "__main__":
    sys.exit(main())

看起来更可能的是,真正的差异是32位和64位。无论如何,请确保您指定了argtypes和restype。看起来真正的区别更可能是32位和64位。无论如何,请确保指定argtypes和restype。